wasm_bindgen_backend/
codegen.rs

1use crate::ast;
2use crate::encode;
3use crate::encode::EncodeChunk;
4use crate::Diagnostic;
5use proc_macro2::{Ident, Span, TokenStream};
6use quote::format_ident;
7use quote::quote_spanned;
8use quote::{quote, ToTokens};
9use std::cell::RefCell;
10use std::collections::{HashMap, HashSet};
11use syn::parse_quote;
12use syn::spanned::Spanned;
13use wasm_bindgen_shared as shared;
14
15/// A trait for converting AST structs into Tokens and adding them to a TokenStream,
16/// or providing a diagnostic if conversion fails.
17pub trait TryToTokens {
18    /// Attempt to convert a `Self` into tokens and add it to the `TokenStream`
19    fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic>;
20
21    /// Attempt to convert a `Self` into a new `TokenStream`
22    fn try_to_token_stream(&self) -> Result<TokenStream, Diagnostic> {
23        let mut tokens = TokenStream::new();
24        self.try_to_tokens(&mut tokens)?;
25        Ok(tokens)
26    }
27}
28
29impl TryToTokens for ast::Program {
30    // Generate wrappers for all the items that we've found
31    fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
32        let mut errors = Vec::new();
33        for export in self.exports.iter() {
34            if let Err(e) = export.try_to_tokens(tokens) {
35                errors.push(e);
36            }
37        }
38        for s in self.structs.iter() {
39            s.to_tokens(tokens);
40        }
41        let mut types = HashMap::new();
42        for i in self.imports.iter() {
43            if let ast::ImportKind::Type(t) = &i.kind {
44                types.insert(t.rust_name.to_string(), t.rust_name.clone());
45            }
46        }
47        for i in self.imports.iter() {
48            DescribeImport {
49                kind: &i.kind,
50                wasm_bindgen: &self.wasm_bindgen,
51            }
52            .to_tokens(tokens);
53
54            // If there is a js namespace, check that name isn't a type. If it is,
55            // this import might be a method on that type.
56            if let Some(nss) = &i.js_namespace {
57                // When the namespace is `A.B`, the type name should be `B`.
58                if let Some(ns) = nss.last().and_then(|t| types.get(t)) {
59                    if i.kind.fits_on_impl() {
60                        let kind = match i.kind.try_to_token_stream() {
61                            Ok(kind) => kind,
62                            Err(e) => {
63                                errors.push(e);
64                                continue;
65                            }
66                        };
67                        (quote! {
68                            #[automatically_derived]
69                            impl #ns { #kind }
70                        })
71                        .to_tokens(tokens);
72                        continue;
73                    }
74                }
75            }
76
77            if let Err(e) = i.kind.try_to_tokens(tokens) {
78                errors.push(e);
79            }
80        }
81        for e in self.enums.iter() {
82            e.to_tokens(tokens);
83        }
84
85        Diagnostic::from_vec(errors)?;
86
87        // Generate a static which will eventually be what lives in a custom section
88        // of the Wasm executable. For now it's just a plain old static, but we'll
89        // eventually have it actually in its own section.
90
91        // See comments in `crates/cli-support/src/lib.rs` about what this
92        // `schema_version` is.
93        let prefix_json = format!(
94            r#"{{"schema_version":"{}","version":"{}"}}"#,
95            shared::SCHEMA_VERSION,
96            shared::version()
97        );
98
99        let wasm_bindgen = &self.wasm_bindgen;
100
101        let encoded = encode::encode(self)?;
102
103        let encoded_chunks: Vec<_> = encoded
104            .custom_section
105            .iter()
106            .map(|chunk| match chunk {
107                EncodeChunk::EncodedBuf(buf) => {
108                    let buf = syn::LitByteStr::new(buf.as_slice(), Span::call_site());
109                    quote!(#buf)
110                }
111                EncodeChunk::StrExpr(expr) => {
112                    // encode expr as str
113                    quote!({
114                        use #wasm_bindgen::__rt::{encode_u32_to_fixed_len_bytes};
115                        const _STR_EXPR: &str = #expr;
116                        const _STR_EXPR_BYTES: &[u8] = _STR_EXPR.as_bytes();
117                        const _STR_EXPR_BYTES_LEN: usize = _STR_EXPR_BYTES.len() + 5;
118                        const _ENCODED_BYTES: [u8; _STR_EXPR_BYTES_LEN] = flat_byte_slices([
119                            &encode_u32_to_fixed_len_bytes(_STR_EXPR_BYTES.len() as u32),
120                            _STR_EXPR_BYTES,
121                        ]);
122                        &_ENCODED_BYTES
123                    })
124                }
125            })
126            .collect();
127
128        let chunk_len = encoded_chunks.len();
129
130        // concatenate all encoded chunks and write the length in front of the chunk;
131        let encode_bytes = quote!({
132            const _CHUNK_SLICES: [&[u8]; #chunk_len] = [
133                #(#encoded_chunks,)*
134            ];
135            #[allow(long_running_const_eval)]
136            const _CHUNK_LEN: usize = flat_len(_CHUNK_SLICES);
137            #[allow(long_running_const_eval)]
138            const _CHUNKS: [u8; _CHUNK_LEN] = flat_byte_slices(_CHUNK_SLICES);
139
140            const _LEN_BYTES: [u8; 4] = (_CHUNK_LEN as u32).to_le_bytes();
141            const _ENCODED_BYTES_LEN: usize = _CHUNK_LEN + 4;
142            #[allow(long_running_const_eval)]
143            const _ENCODED_BYTES: [u8; _ENCODED_BYTES_LEN] = flat_byte_slices([&_LEN_BYTES, &_CHUNKS]);
144            &_ENCODED_BYTES
145        });
146
147        // We already consumed the contents of included files when generating
148        // the custom section, but we want to make sure that updates to the
149        // generated files will cause this macro to rerun incrementally. To do
150        // that we use `include_str!` to force rustc to think it has a
151        // dependency on these files. That way when the file changes Cargo will
152        // automatically rerun rustc which will rerun this macro. Other than
153        // this we don't actually need the results of the `include_str!`, so
154        // it's just shoved into an anonymous static.
155        let file_dependencies = encoded.included_files.iter().map(|file| {
156            let file = file.to_str().unwrap();
157            quote! { include_str!(#file) }
158        });
159
160        let len = prefix_json.len() as u32;
161        let prefix_json_bytes = [&len.to_le_bytes()[..], prefix_json.as_bytes()].concat();
162        let prefix_json_bytes = syn::LitByteStr::new(&prefix_json_bytes, Span::call_site());
163
164        (quote! {
165            #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
166            #[automatically_derived]
167            const _: () = {
168                use #wasm_bindgen::__rt::{flat_len, flat_byte_slices};
169
170                static _INCLUDED_FILES: &[&str] = &[#(#file_dependencies),*];
171
172                const _ENCODED_BYTES: &[u8] = #encode_bytes;
173                const _PREFIX_JSON_BYTES: &[u8] = #prefix_json_bytes;
174                const _ENCODED_BYTES_LEN: usize  = _ENCODED_BYTES.len();
175                const _PREFIX_JSON_BYTES_LEN: usize =  _PREFIX_JSON_BYTES.len();
176                const _LEN: usize = _PREFIX_JSON_BYTES_LEN + _ENCODED_BYTES_LEN;
177
178                #[link_section = "__wasm_bindgen_unstable"]
179                #[allow(long_running_const_eval)]
180                static _GENERATED: [u8; _LEN] = flat_byte_slices([_PREFIX_JSON_BYTES, _ENCODED_BYTES]);
181            };
182        })
183        .to_tokens(tokens);
184
185        Ok(())
186    }
187}
188
189impl TryToTokens for ast::LinkToModule {
190    fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
191        let mut program = TokenStream::new();
192        self.0.try_to_tokens(&mut program)?;
193        let link_function_name = self.0.link_function_name(0);
194        let name = Ident::new(&link_function_name, Span::call_site());
195        let wasm_bindgen = &self.0.wasm_bindgen;
196        let abi_ret = quote! { #wasm_bindgen::convert::WasmRet<<#wasm_bindgen::__rt::alloc::string::String as #wasm_bindgen::convert::FromWasmAbi>::Abi> };
197        let extern_fn = extern_fn(&name, &[], &[], &[], abi_ret);
198        (quote! {
199            {
200                #program
201                #extern_fn
202
203                static __VAL: #wasm_bindgen::__rt::LazyLock<#wasm_bindgen::__rt::alloc::string::String> =
204                    #wasm_bindgen::__rt::LazyLock::new(|| unsafe {
205                        <#wasm_bindgen::__rt::alloc::string::String as #wasm_bindgen::convert::FromWasmAbi>::from_abi(#name().join())
206                    });
207
208                #wasm_bindgen::__rt::alloc::string::String::clone(&__VAL)
209            }
210        })
211        .to_tokens(tokens);
212        Ok(())
213    }
214}
215
216impl ToTokens for ast::Struct {
217    fn to_tokens(&self, tokens: &mut TokenStream) {
218        let name = &self.rust_name;
219        let name_str = self.js_name.to_string();
220        let name_len = name_str.len() as u32;
221        let name_chars: Vec<u32> = name_str.chars().map(|c| c as u32).collect();
222        let new_fn = Ident::new(&shared::new_function(&name_str), Span::call_site());
223        let free_fn = Ident::new(&shared::free_function(&name_str), Span::call_site());
224        let unwrap_fn = Ident::new(&shared::unwrap_function(&name_str), Span::call_site());
225        let wasm_bindgen = &self.wasm_bindgen;
226        (quote! {
227            #[automatically_derived]
228            impl #wasm_bindgen::__rt::marker::SupportsConstructor for #name {}
229            #[automatically_derived]
230            impl #wasm_bindgen::__rt::marker::SupportsInstanceProperty for #name {}
231            #[automatically_derived]
232            impl #wasm_bindgen::__rt::marker::SupportsStaticProperty for #name {}
233
234            #[automatically_derived]
235            impl #wasm_bindgen::describe::WasmDescribe for #name {
236                fn describe() {
237                    use #wasm_bindgen::describe::*;
238                    inform(RUST_STRUCT);
239                    inform(#name_len);
240                    #(inform(#name_chars);)*
241                }
242            }
243
244            #[automatically_derived]
245            impl #wasm_bindgen::convert::IntoWasmAbi for #name {
246                type Abi = u32;
247
248                fn into_abi(self) -> u32 {
249                    use #wasm_bindgen::__rt::alloc::rc::Rc;
250                    use #wasm_bindgen::__rt::WasmRefCell;
251                    Rc::into_raw(Rc::new(WasmRefCell::new(self))) as u32
252                }
253            }
254
255            #[automatically_derived]
256            impl #wasm_bindgen::convert::FromWasmAbi for #name {
257                type Abi = u32;
258
259                unsafe fn from_abi(js: u32) -> Self {
260                    use #wasm_bindgen::__rt::alloc::rc::Rc;
261                    use #wasm_bindgen::__rt::core::result::Result::{Ok, Err};
262                    use #wasm_bindgen::__rt::{assert_not_null, WasmRefCell};
263
264                    let ptr = js as *mut WasmRefCell<#name>;
265                    assert_not_null(ptr);
266                    let rc = Rc::from_raw(ptr);
267                    match Rc::try_unwrap(rc) {
268                        Ok(cell) => cell.into_inner(),
269                        Err(_) => #wasm_bindgen::throw_str(
270                            "attempted to take ownership of Rust value while it was borrowed"
271                        ),
272                    }
273                }
274            }
275
276            #[automatically_derived]
277            impl #wasm_bindgen::__rt::core::convert::From<#name> for
278                #wasm_bindgen::JsValue
279            {
280                fn from(value: #name) -> Self {
281                    let ptr = #wasm_bindgen::convert::IntoWasmAbi::into_abi(value);
282
283                    #[link(wasm_import_module = "__wbindgen_placeholder__")]
284                    #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
285                    extern "C" {
286                        fn #new_fn(ptr: u32) -> u32;
287                    }
288
289                    #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
290                    unsafe fn #new_fn(_: u32) -> u32 {
291                        panic!("cannot convert to JsValue outside of the Wasm target")
292                    }
293
294                    unsafe {
295                        <#wasm_bindgen::JsValue as #wasm_bindgen::convert::FromWasmAbi>
296                            ::from_abi(#new_fn(ptr))
297                    }
298                }
299            }
300
301            #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
302            #[automatically_derived]
303            const _: () = {
304                #wasm_bindgen::__wbindgen_coverage! {
305                #[no_mangle]
306                #[doc(hidden)]
307                // `allow_delayed` is whether it's ok to not actually free the `ptr` immediately
308                // if it's still borrowed.
309                pub unsafe extern "C" fn #free_fn(ptr: u32, allow_delayed: u32) {
310                    use #wasm_bindgen::__rt::alloc::rc::Rc;
311
312                    if allow_delayed != 0 {
313                        // Just drop the implicit `Rc` owned by JS, and then if the value is still
314                        // referenced it'll be kept alive by its other `Rc`s.
315                        let ptr = ptr as *mut #wasm_bindgen::__rt::WasmRefCell<#name>;
316                        #wasm_bindgen::__rt::assert_not_null(ptr);
317                        drop(Rc::from_raw(ptr));
318                    } else {
319                        // Claim ownership of the value, which will panic if it's borrowed.
320                        let _ = <#name as #wasm_bindgen::convert::FromWasmAbi>::from_abi(ptr);
321                    }
322                }
323                }
324            };
325
326            #[automatically_derived]
327            impl #wasm_bindgen::convert::RefFromWasmAbi for #name {
328                type Abi = u32;
329                type Anchor = #wasm_bindgen::__rt::RcRef<#name>;
330
331                unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
332                    use #wasm_bindgen::__rt::alloc::rc::Rc;
333
334                    let js = js as *mut #wasm_bindgen::__rt::WasmRefCell<#name>;
335                    #wasm_bindgen::__rt::assert_not_null(js);
336
337                    Rc::increment_strong_count(js);
338                    let rc = Rc::from_raw(js);
339                    #wasm_bindgen::__rt::RcRef::new(rc)
340                }
341            }
342
343            #[automatically_derived]
344            impl #wasm_bindgen::convert::RefMutFromWasmAbi for #name {
345                type Abi = u32;
346                type Anchor = #wasm_bindgen::__rt::RcRefMut<#name>;
347
348                unsafe fn ref_mut_from_abi(js: Self::Abi) -> Self::Anchor {
349                    use #wasm_bindgen::__rt::alloc::rc::Rc;
350
351                    let js = js as *mut #wasm_bindgen::__rt::WasmRefCell<#name>;
352                    #wasm_bindgen::__rt::assert_not_null(js);
353
354                    Rc::increment_strong_count(js);
355                    let rc = Rc::from_raw(js);
356                    #wasm_bindgen::__rt::RcRefMut::new(rc)
357                }
358            }
359
360            #[automatically_derived]
361            impl #wasm_bindgen::convert::LongRefFromWasmAbi for #name {
362                type Abi = u32;
363                type Anchor = #wasm_bindgen::__rt::RcRef<#name>;
364
365                unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor {
366                    <Self as #wasm_bindgen::convert::RefFromWasmAbi>::ref_from_abi(js)
367                }
368            }
369
370            #[automatically_derived]
371            impl #wasm_bindgen::convert::OptionIntoWasmAbi for #name {
372                #[inline]
373                fn none() -> Self::Abi { 0 }
374            }
375
376            #[automatically_derived]
377            impl #wasm_bindgen::convert::OptionFromWasmAbi for #name {
378                #[inline]
379                fn is_none(abi: &Self::Abi) -> bool { *abi == 0 }
380            }
381
382            #[automatically_derived]
383            impl #wasm_bindgen::convert::TryFromJsValue for #name {
384                type Error = #wasm_bindgen::JsValue;
385
386                fn try_from_js_value(value: #wasm_bindgen::JsValue)
387                    -> #wasm_bindgen::__rt::core::result::Result<Self, Self::Error> {
388                    let idx = #wasm_bindgen::convert::IntoWasmAbi::into_abi(&value);
389
390                    #[link(wasm_import_module = "__wbindgen_placeholder__")]
391                    #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
392                    extern "C" {
393                        fn #unwrap_fn(ptr: u32) -> u32;
394                    }
395
396                    #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
397                    unsafe fn #unwrap_fn(_: u32) -> u32 {
398                        panic!("cannot convert from JsValue outside of the Wasm target")
399                    }
400
401                    let ptr = unsafe { #unwrap_fn(idx) };
402                    if ptr == 0 {
403                        #wasm_bindgen::__rt::core::result::Result::Err(value)
404                    } else {
405                        // Don't run `JsValue`'s destructor, `unwrap_fn` already did that for us.
406                        #[allow(clippy::mem_forget)]
407                        #wasm_bindgen::__rt::core::mem::forget(value);
408                        unsafe {
409                            #wasm_bindgen::__rt::core::result::Result::Ok(
410                                <Self as #wasm_bindgen::convert::FromWasmAbi>::from_abi(ptr)
411                            )
412                        }
413                    }
414                }
415            }
416
417            #[automatically_derived]
418            impl #wasm_bindgen::describe::WasmDescribeVector for #name {
419                fn describe_vector() {
420                    use #wasm_bindgen::describe::*;
421                    inform(VECTOR);
422                    inform(NAMED_EXTERNREF);
423                    inform(#name_len);
424                    #(inform(#name_chars);)*
425                }
426            }
427
428            #[automatically_derived]
429            impl #wasm_bindgen::convert::VectorIntoWasmAbi for #name {
430                type Abi = <
431                    #wasm_bindgen::__rt::alloc::boxed::Box<[#wasm_bindgen::JsValue]>
432                    as #wasm_bindgen::convert::IntoWasmAbi
433                >::Abi;
434
435                fn vector_into_abi(
436                    vector: #wasm_bindgen::__rt::alloc::boxed::Box<[#name]>
437                ) -> Self::Abi {
438                    #wasm_bindgen::convert::js_value_vector_into_abi(vector)
439                }
440            }
441
442            #[automatically_derived]
443            impl #wasm_bindgen::convert::VectorFromWasmAbi for #name {
444                type Abi = <
445                    #wasm_bindgen::__rt::alloc::boxed::Box<[#wasm_bindgen::JsValue]>
446                    as #wasm_bindgen::convert::FromWasmAbi
447                >::Abi;
448
449                unsafe fn vector_from_abi(
450                    js: Self::Abi
451                ) -> #wasm_bindgen::__rt::alloc::boxed::Box<[#name]> {
452                    #wasm_bindgen::convert::js_value_vector_from_abi(js)
453                }
454            }
455        })
456        .to_tokens(tokens);
457
458        for field in self.fields.iter() {
459            field.to_tokens(tokens);
460        }
461    }
462}
463
464impl ToTokens for ast::StructField {
465    fn to_tokens(&self, tokens: &mut TokenStream) {
466        let rust_name = &self.rust_name;
467        let struct_name = &self.struct_name;
468        let ty = &self.ty;
469        let getter = &self.getter;
470        let setter = &self.setter;
471
472        let maybe_assert_copy = if self.getter_with_clone.is_some() {
473            quote! {}
474        } else {
475            quote! { assert_copy::<#ty>() }
476        };
477        let maybe_assert_copy = respan(maybe_assert_copy, ty);
478
479        // Split this out so that it isn't affected by `quote_spanned!`.
480        //
481        // If we don't do this, it might end up being unable to reference `js`
482        // properly because it doesn't have the same span.
483        //
484        // See https://github.com/wasm-bindgen/wasm-bindgen/pull/3725.
485        let js_token = quote! { js };
486        let mut val = quote_spanned!(self.rust_name.span()=> (*#js_token).borrow().#rust_name);
487        if let Some(span) = self.getter_with_clone {
488            val = quote_spanned!(span=> <#ty as Clone>::clone(&#val) );
489        }
490
491        let wasm_bindgen = &self.wasm_bindgen;
492
493        (quote! {
494            #[automatically_derived]
495            const _: () = {
496                #wasm_bindgen::__wbindgen_coverage! {
497                #[cfg_attr(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")), no_mangle)]
498                #[doc(hidden)]
499                pub unsafe extern "C" fn #getter(js: u32)
500                    -> #wasm_bindgen::convert::WasmRet<<#ty as #wasm_bindgen::convert::IntoWasmAbi>::Abi>
501                {
502                    use #wasm_bindgen::__rt::{WasmRefCell, assert_not_null};
503                    use #wasm_bindgen::convert::IntoWasmAbi;
504
505                    fn assert_copy<T: Copy>(){}
506                    #maybe_assert_copy;
507
508                    let js = js as *mut WasmRefCell<#struct_name>;
509                    assert_not_null(js);
510                    let val = #val;
511                    <#ty as IntoWasmAbi>::into_abi(val).into()
512                }
513                }
514            };
515        })
516        .to_tokens(tokens);
517
518        Descriptor {
519            ident: getter,
520            inner: quote! {
521                <#ty as WasmDescribe>::describe();
522            },
523            attrs: vec![],
524            wasm_bindgen: &self.wasm_bindgen,
525        }
526        .to_tokens(tokens);
527
528        if self.readonly {
529            return;
530        }
531
532        let abi = quote! { <#ty as #wasm_bindgen::convert::FromWasmAbi>::Abi };
533        let (args, names) = splat(wasm_bindgen, &Ident::new("val", rust_name.span()), &abi);
534
535        (quote! {
536            #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
537            #[automatically_derived]
538            const _: () = {
539                #wasm_bindgen::__wbindgen_coverage! {
540                #[no_mangle]
541                #[doc(hidden)]
542                pub unsafe extern "C" fn #setter(
543                    js: u32,
544                    #(#args,)*
545                ) {
546                    use #wasm_bindgen::__rt::{WasmRefCell, assert_not_null};
547                    use #wasm_bindgen::convert::FromWasmAbi;
548
549                    let js = js as *mut WasmRefCell<#struct_name>;
550                    assert_not_null(js);
551                    let val = <#abi as #wasm_bindgen::convert::WasmAbi>::join(#(#names),*);
552                    let val = <#ty as FromWasmAbi>::from_abi(val);
553                    (*js).borrow_mut().#rust_name = val;
554                }
555                }
556            };
557        })
558        .to_tokens(tokens);
559    }
560}
561
562impl TryToTokens for ast::Export {
563    fn try_to_tokens(self: &ast::Export, into: &mut TokenStream) -> Result<(), Diagnostic> {
564        let generated_name = self.rust_symbol();
565        let export_name = self.export_name();
566        let mut args = vec![];
567        let mut arg_conversions = vec![];
568        let mut converted_arguments = vec![];
569        let ret = Ident::new("_ret", Span::call_site());
570
571        let offset = if self.method_self.is_some() {
572            args.push(quote! { me: u32 });
573            1
574        } else {
575            0
576        };
577
578        let name = &self.rust_name;
579        let wasm_bindgen = &self.wasm_bindgen;
580        let wasm_bindgen_futures = &self.wasm_bindgen_futures;
581        let receiver = match self.method_self {
582            Some(ast::MethodSelf::ByValue) => {
583                let class = self.rust_class.as_ref().unwrap();
584                arg_conversions.push(quote! {
585                    let me = unsafe {
586                        <#class as #wasm_bindgen::convert::FromWasmAbi>::from_abi(me)
587                    };
588                });
589                quote! { me.#name }
590            }
591            Some(ast::MethodSelf::RefMutable) => {
592                let class = self.rust_class.as_ref().unwrap();
593                arg_conversions.push(quote! {
594                    let mut me = unsafe {
595                        <#class as #wasm_bindgen::convert::RefMutFromWasmAbi>
596                            ::ref_mut_from_abi(me)
597                    };
598                    let me = &mut *me;
599                });
600                quote! { me.#name }
601            }
602            Some(ast::MethodSelf::RefShared) => {
603                let class = self.rust_class.as_ref().unwrap();
604                let (trait_, func, borrow) = if self.function.r#async {
605                    (
606                        quote!(LongRefFromWasmAbi),
607                        quote!(long_ref_from_abi),
608                        quote!(
609                            <<#class as #wasm_bindgen::convert::LongRefFromWasmAbi>
610                                ::Anchor as #wasm_bindgen::__rt::core::borrow::Borrow<#class>>
611                                ::borrow(&me)
612                        ),
613                    )
614                } else {
615                    (quote!(RefFromWasmAbi), quote!(ref_from_abi), quote!(&*me))
616                };
617                arg_conversions.push(quote! {
618                    let me = unsafe {
619                        <#class as #wasm_bindgen::convert::#trait_>::#func(me)
620                    };
621                    let me = #borrow;
622                });
623                quote! { me.#name }
624            }
625            None => match &self.rust_class {
626                Some(class) => quote! { #class::#name },
627                None => quote! { #name },
628            },
629        };
630
631        let mut argtys = Vec::new();
632        for (i, arg) in self.function.arguments.iter().enumerate() {
633            argtys.push(&*arg.pat_type.ty);
634            let i = i + offset;
635            let ident = Ident::new(&format!("arg{}", i), Span::call_site());
636            fn unwrap_nested_types(ty: &syn::Type) -> &syn::Type {
637                match &ty {
638                    syn::Type::Group(syn::TypeGroup { ref elem, .. }) => unwrap_nested_types(elem),
639                    syn::Type::Paren(syn::TypeParen { ref elem, .. }) => unwrap_nested_types(elem),
640                    _ => ty,
641                }
642            }
643            let ty = unwrap_nested_types(&arg.pat_type.ty);
644
645            match &ty {
646                syn::Type::Reference(syn::TypeReference {
647                    mutability: Some(_),
648                    elem,
649                    ..
650                }) => {
651                    let abi = quote! { <#elem as #wasm_bindgen::convert::RefMutFromWasmAbi>::Abi };
652                    let (prim_args, prim_names) = splat(wasm_bindgen, &ident, &abi);
653                    args.extend(prim_args);
654                    arg_conversions.push(quote! {
655                        let mut #ident = unsafe {
656                            <#elem as #wasm_bindgen::convert::RefMutFromWasmAbi>
657                                ::ref_mut_from_abi(
658                                    <#abi as #wasm_bindgen::convert::WasmAbi>::join(#(#prim_names),*)
659                                )
660                        };
661                        let #ident = &mut *#ident;
662                    });
663                }
664                syn::Type::Reference(syn::TypeReference { elem, .. }) => {
665                    if self.function.r#async {
666                        let abi =
667                            quote! { <#elem as #wasm_bindgen::convert::LongRefFromWasmAbi>::Abi };
668                        let (prim_args, prim_names) = splat(wasm_bindgen, &ident, &abi);
669                        args.extend(prim_args);
670                        arg_conversions.push(quote! {
671                            let #ident = unsafe {
672                                <#elem as #wasm_bindgen::convert::LongRefFromWasmAbi>
673                                    ::long_ref_from_abi(
674                                        <#abi as #wasm_bindgen::convert::WasmAbi>::join(#(#prim_names),*)
675                                    )
676                            };
677                            let #ident = <<#elem as #wasm_bindgen::convert::LongRefFromWasmAbi>
678                                ::Anchor as core::borrow::Borrow<#elem>>
679                                ::borrow(&#ident);
680                        });
681                    } else {
682                        let abi = quote! { <#elem as #wasm_bindgen::convert::RefFromWasmAbi>::Abi };
683                        let (prim_args, prim_names) = splat(wasm_bindgen, &ident, &abi);
684                        args.extend(prim_args);
685                        arg_conversions.push(quote! {
686                            let #ident = unsafe {
687                                <#elem as #wasm_bindgen::convert::RefFromWasmAbi>
688                                    ::ref_from_abi(
689                                        <#abi as #wasm_bindgen::convert::WasmAbi>::join(#(#prim_names),*)
690                                    )
691                            };
692                            let #ident = &*#ident;
693                        });
694                    }
695                }
696                _ => {
697                    let abi = quote! { <#ty as #wasm_bindgen::convert::FromWasmAbi>::Abi };
698                    let (prim_args, prim_names) = splat(wasm_bindgen, &ident, &abi);
699                    args.extend(prim_args);
700                    arg_conversions.push(quote! {
701                        let #ident = unsafe {
702                            <#ty as #wasm_bindgen::convert::FromWasmAbi>
703                                ::from_abi(
704                                    <#abi as #wasm_bindgen::convert::WasmAbi>::join(#(#prim_names),*)
705                                )
706                        };
707                    });
708                }
709            }
710            converted_arguments.push(quote! { #ident });
711        }
712        let syn_unit = syn::Type::Tuple(syn::TypeTuple {
713            elems: Default::default(),
714            paren_token: Default::default(),
715        });
716        let syn_ret = self
717            .function
718            .ret
719            .as_ref()
720            .map(|ret| &ret.r#type)
721            .unwrap_or(&syn_unit);
722        if let syn::Type::Reference(_) = syn_ret {
723            bail_span!(syn_ret, "cannot return a borrowed ref with #[wasm_bindgen]",)
724        }
725
726        // For an `async` function we always run it through `future_to_promise`
727        // since we're returning a promise to JS, and this will implicitly
728        // require that the function returns a `Future<Output = Result<...>>`
729        let (ret_ty, inner_ret_ty, ret_expr) = if self.function.r#async {
730            if self.start {
731                (
732                    quote! { () },
733                    quote! { () },
734                    quote! {
735                        <#syn_ret as #wasm_bindgen::__rt::Start>::start(#ret.await)
736                    },
737                )
738            } else {
739                (
740                    quote! { #wasm_bindgen::JsValue },
741                    quote! { #syn_ret },
742                    quote! {
743                        <#syn_ret as #wasm_bindgen::__rt::IntoJsResult>::into_js_result(#ret.await)
744                    },
745                )
746            }
747        } else if self.start {
748            (
749                quote! { () },
750                quote! { () },
751                quote! { <#syn_ret as #wasm_bindgen::__rt::Start>::start(#ret) },
752            )
753        } else {
754            (quote! { #syn_ret }, quote! { #syn_ret }, quote! { #ret })
755        };
756
757        let mut call = quote! {
758            {
759                #(#arg_conversions)*
760                let #ret = #receiver(#(#converted_arguments),*);
761                #ret_expr
762            }
763        };
764
765        if self.function.r#async {
766            if self.start {
767                call = quote! {
768                    #wasm_bindgen_futures::spawn_local(async move {
769                        #call
770                    })
771                }
772            } else {
773                call = quote! {
774                    #wasm_bindgen_futures::future_to_promise(async move {
775                        #call
776                    }).into()
777                }
778            }
779        }
780
781        let projection = quote! { <#ret_ty as #wasm_bindgen::convert::ReturnWasmAbi> };
782        let convert_ret = quote! { #projection::return_abi(#ret).into() };
783        let describe_ret = quote! {
784            <#ret_ty as WasmDescribe>::describe();
785            <#inner_ret_ty as WasmDescribe>::describe();
786        };
787        let nargs = self.function.arguments.len() as u32;
788        let attrs = &self.function.rust_attrs;
789
790        let mut checks = Vec::new();
791        if self.start {
792            checks.push(quote! { const _ASSERT: fn() = || -> #projection::Abi { loop {} }; });
793        };
794
795        if let Some(class) = self.rust_class.as_ref() {
796            // little helper function to make sure the check points to the
797            // location of the function causing the assert to fail
798            let mut add_check = |token_stream| {
799                checks.push(respan(token_stream, &self.rust_name));
800            };
801
802            match &self.method_kind {
803                ast::MethodKind::Constructor => {
804                    add_check(quote! {
805                        let _: #wasm_bindgen::__rt::marker::CheckSupportsConstructor<#class>;
806                    });
807
808                    if self.function.r#async {
809                        (quote_spanned! {
810                            self.function.name_span =>
811                            const _: () = {
812                                #[deprecated(note = "async constructors produce invalid TS code and support will be removed in the future")]
813                                const fn constructor() {}
814                                constructor();
815                            };
816                        })
817                        .to_tokens(into);
818                    }
819                }
820                ast::MethodKind::Operation(operation) => match operation.kind {
821                    ast::OperationKind::Getter(_) | ast::OperationKind::Setter(_) => {
822                        if operation.is_static {
823                            add_check(quote! {
824                                let _: #wasm_bindgen::__rt::marker::CheckSupportsStaticProperty<#class>;
825                            });
826                        } else {
827                            add_check(quote! {
828                                let _: #wasm_bindgen::__rt::marker::CheckSupportsInstanceProperty<#class>;
829                            });
830                        }
831                    }
832                    _ => {}
833                },
834            }
835        }
836
837        (quote! {
838            #[automatically_derived]
839            const _: () = {
840                #wasm_bindgen::__wbindgen_coverage! {
841                #(#attrs)*
842                #[cfg_attr(
843                    all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")),
844                    export_name = #export_name,
845                )]
846                pub unsafe extern "C" fn #generated_name(#(#args),*) -> #wasm_bindgen::convert::WasmRet<#projection::Abi> {
847                    const _: () = {
848                        #(#checks)*
849                    };
850
851                    let #ret = #call;
852                    #convert_ret
853                }
854                }
855            };
856        })
857        .to_tokens(into);
858
859        let describe_args: TokenStream = argtys
860            .iter()
861            .map(|ty| match ty {
862                syn::Type::Reference(reference)
863                    if self.function.r#async && reference.mutability.is_none() =>
864                {
865                    let inner = &reference.elem;
866                    quote! {
867                        inform(LONGREF);
868                        <#inner as WasmDescribe>::describe();
869                    }
870                }
871                _ => quote! { <#ty as WasmDescribe>::describe(); },
872            })
873            .collect();
874
875        // In addition to generating the shim function above which is what
876        // our generated JS will invoke, we *also* generate a "descriptor"
877        // shim. This descriptor shim uses the `WasmDescribe` trait to
878        // programmatically describe the type signature of the generated
879        // shim above. This in turn is then used to inform the
880        // `wasm-bindgen` CLI tool exactly what types and such it should be
881        // using in JS.
882        //
883        // Note that this descriptor function is a purely an internal detail
884        // of `#[wasm_bindgen]` and isn't intended to be exported to anyone
885        // or actually part of the final was binary. Additionally, this is
886        // literally executed when the `wasm-bindgen` tool executes.
887        //
888        // In any case, there's complications in `wasm-bindgen` to handle
889        // this, but the tl;dr; is that this is stripped from the final wasm
890        // binary along with anything it references.
891        let export = Ident::new(&export_name, Span::call_site());
892        Descriptor {
893            ident: &export,
894            inner: quote! {
895                inform(FUNCTION);
896                inform(0);
897                inform(#nargs);
898                #describe_args
899                #describe_ret
900            },
901            attrs: attrs.clone(),
902            wasm_bindgen: &self.wasm_bindgen,
903        }
904        .to_tokens(into);
905
906        Ok(())
907    }
908}
909
910impl TryToTokens for ast::ImportKind {
911    fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
912        match *self {
913            ast::ImportKind::Function(ref f) => f.try_to_tokens(tokens)?,
914            ast::ImportKind::Static(ref s) => s.to_tokens(tokens),
915            ast::ImportKind::String(ref s) => s.to_tokens(tokens),
916            ast::ImportKind::Type(ref t) => t.to_tokens(tokens),
917            ast::ImportKind::Enum(ref e) => e.to_tokens(tokens),
918        }
919
920        Ok(())
921    }
922}
923
924impl ToTokens for ast::ImportType {
925    fn to_tokens(&self, tokens: &mut TokenStream) {
926        let vis = &self.vis;
927        let rust_name = &self.rust_name;
928        let attrs = &self.attrs;
929        let doc_comment = match &self.doc_comment {
930            None => "",
931            Some(comment) => comment,
932        };
933        let instanceof_shim = Ident::new(&self.instanceof_shim, Span::call_site());
934
935        let wasm_bindgen = &self.wasm_bindgen;
936        let internal_obj = match self.extends.first() {
937            Some(target) => {
938                quote! { #target }
939            }
940            None => {
941                quote! { #wasm_bindgen::JsValue }
942            }
943        };
944
945        let description = if let Some(typescript_type) = &self.typescript_type {
946            let typescript_type_len = typescript_type.len() as u32;
947            let typescript_type_chars = typescript_type.chars().map(|c| c as u32);
948            quote! {
949                use #wasm_bindgen::describe::*;
950                inform(NAMED_EXTERNREF);
951                inform(#typescript_type_len);
952                #(inform(#typescript_type_chars);)*
953            }
954        } else {
955            quote! {
956                JsValue::describe()
957            }
958        };
959
960        let is_type_of = self.is_type_of.as_ref().map(|is_type_of| {
961            quote! {
962                #[inline]
963                fn is_type_of(val: &JsValue) -> bool {
964                    let is_type_of: fn(&JsValue) -> bool = #is_type_of;
965                    is_type_of(val)
966                }
967            }
968        });
969
970        let no_deref = self.no_deref;
971
972        let doc = if doc_comment.is_empty() {
973            quote! {}
974        } else {
975            quote! {
976                #[doc = #doc_comment]
977            }
978        };
979
980        (quote! {
981            #[automatically_derived]
982            #(#attrs)*
983            #doc
984            #[repr(transparent)]
985            #vis struct #rust_name {
986                obj: #internal_obj
987            }
988
989            #[automatically_derived]
990            const _: () = {
991                use #wasm_bindgen::convert::TryFromJsValue;
992                use #wasm_bindgen::convert::{IntoWasmAbi, FromWasmAbi};
993                use #wasm_bindgen::convert::{OptionIntoWasmAbi, OptionFromWasmAbi};
994                use #wasm_bindgen::convert::{RefFromWasmAbi, LongRefFromWasmAbi};
995                use #wasm_bindgen::describe::WasmDescribe;
996                use #wasm_bindgen::{JsValue, JsCast};
997                use #wasm_bindgen::__rt::core;
998
999                #[automatically_derived]
1000                impl WasmDescribe for #rust_name {
1001                    fn describe() {
1002                        #description
1003                    }
1004                }
1005
1006                #[automatically_derived]
1007                impl IntoWasmAbi for #rust_name {
1008                    type Abi = <JsValue as IntoWasmAbi>::Abi;
1009
1010                    #[inline]
1011                    fn into_abi(self) -> Self::Abi {
1012                        self.obj.into_abi()
1013                    }
1014                }
1015
1016                #[automatically_derived]
1017                impl OptionIntoWasmAbi for #rust_name {
1018                    #[inline]
1019                    fn none() -> Self::Abi {
1020                        0
1021                    }
1022                }
1023
1024                #[automatically_derived]
1025                impl<'a> OptionIntoWasmAbi for &'a #rust_name {
1026                    #[inline]
1027                    fn none() -> Self::Abi {
1028                        0
1029                    }
1030                }
1031
1032                #[automatically_derived]
1033                impl FromWasmAbi for #rust_name {
1034                    type Abi = <JsValue as FromWasmAbi>::Abi;
1035
1036                    #[inline]
1037                    unsafe fn from_abi(js: Self::Abi) -> Self {
1038                        #rust_name {
1039                            obj: JsValue::from_abi(js).into(),
1040                        }
1041                    }
1042                }
1043
1044                #[automatically_derived]
1045                impl OptionFromWasmAbi for #rust_name {
1046                    #[inline]
1047                    fn is_none(abi: &Self::Abi) -> bool { *abi == 0 }
1048                }
1049
1050                #[automatically_derived]
1051                impl<'a> IntoWasmAbi for &'a #rust_name {
1052                    type Abi = <&'a JsValue as IntoWasmAbi>::Abi;
1053
1054                    #[inline]
1055                    fn into_abi(self) -> Self::Abi {
1056                        (&self.obj).into_abi()
1057                    }
1058                }
1059
1060                #[automatically_derived]
1061                impl RefFromWasmAbi for #rust_name {
1062                    type Abi = <JsValue as RefFromWasmAbi>::Abi;
1063                    type Anchor = core::mem::ManuallyDrop<#rust_name>;
1064
1065                    #[inline]
1066                    unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
1067                        let tmp = <JsValue as RefFromWasmAbi>::ref_from_abi(js);
1068                        core::mem::ManuallyDrop::new(#rust_name {
1069                            obj: core::mem::ManuallyDrop::into_inner(tmp).into(),
1070                        })
1071                    }
1072                }
1073
1074                #[automatically_derived]
1075                impl LongRefFromWasmAbi for #rust_name {
1076                    type Abi = <JsValue as LongRefFromWasmAbi>::Abi;
1077                    type Anchor = #rust_name;
1078
1079                    #[inline]
1080                    unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor {
1081                        let tmp = <JsValue as LongRefFromWasmAbi>::long_ref_from_abi(js);
1082                        #rust_name { obj: tmp.into() }
1083                    }
1084                }
1085
1086                // TODO: remove this on the next major version
1087                #[automatically_derived]
1088                impl From<JsValue> for #rust_name {
1089                    #[inline]
1090                    fn from(obj: JsValue) -> #rust_name {
1091                        #rust_name { obj: obj.into() }
1092                    }
1093                }
1094
1095                #[automatically_derived]
1096                impl AsRef<JsValue> for #rust_name {
1097                    #[inline]
1098                    fn as_ref(&self) -> &JsValue { self.obj.as_ref() }
1099                }
1100
1101                #[automatically_derived]
1102                impl AsRef<#rust_name> for #rust_name {
1103                    #[inline]
1104                    fn as_ref(&self) -> &#rust_name { self }
1105                }
1106
1107
1108                #[automatically_derived]
1109                impl From<#rust_name> for JsValue {
1110                    #[inline]
1111                    fn from(obj: #rust_name) -> JsValue {
1112                        obj.obj.into()
1113                    }
1114                }
1115
1116                #[automatically_derived]
1117                impl JsCast for #rust_name {
1118                    fn instanceof(val: &JsValue) -> bool {
1119                        #[link(wasm_import_module = "__wbindgen_placeholder__")]
1120                        #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
1121                        extern "C" {
1122                            fn #instanceof_shim(val: u32) -> u32;
1123                        }
1124                        #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
1125                        unsafe fn #instanceof_shim(_: u32) -> u32 {
1126                            panic!("cannot check instanceof on non-wasm targets");
1127                        }
1128                        unsafe {
1129                            let idx = val.into_abi();
1130                            #instanceof_shim(idx) != 0
1131                        }
1132                    }
1133
1134                    #is_type_of
1135
1136                    #[inline]
1137                    fn unchecked_from_js(val: JsValue) -> Self {
1138                        #rust_name { obj: val.into() }
1139                    }
1140
1141                    #[inline]
1142                    fn unchecked_from_js_ref(val: &JsValue) -> &Self {
1143                        // Should be safe because `#rust_name` is a transparent
1144                        // wrapper around `val`
1145                        unsafe { &*(val as *const JsValue as *const #rust_name) }
1146                    }
1147                }
1148            };
1149        })
1150        .to_tokens(tokens);
1151
1152        if !no_deref {
1153            (quote! {
1154                #[automatically_derived]
1155                impl #wasm_bindgen::__rt::core::ops::Deref for #rust_name {
1156                    type Target = #internal_obj;
1157
1158                    #[inline]
1159                    fn deref(&self) -> &#internal_obj {
1160                        &self.obj
1161                    }
1162                }
1163            })
1164            .to_tokens(tokens);
1165        }
1166
1167        for superclass in self.extends.iter() {
1168            (quote! {
1169                #[automatically_derived]
1170                impl From<#rust_name> for #superclass {
1171                    #[inline]
1172                    fn from(obj: #rust_name) -> #superclass {
1173                        use #wasm_bindgen::JsCast;
1174                        #superclass::unchecked_from_js(obj.into())
1175                    }
1176                }
1177
1178                #[automatically_derived]
1179                impl AsRef<#superclass> for #rust_name {
1180                    #[inline]
1181                    fn as_ref(&self) -> &#superclass {
1182                        use #wasm_bindgen::JsCast;
1183                        #superclass::unchecked_from_js_ref(self.as_ref())
1184                    }
1185                }
1186            })
1187            .to_tokens(tokens);
1188        }
1189    }
1190}
1191
1192impl ToTokens for ast::StringEnum {
1193    fn to_tokens(&self, tokens: &mut TokenStream) {
1194        let vis = &self.vis;
1195        let enum_name = &self.name;
1196        let name_str = &self.js_name;
1197        let name_len = name_str.len() as u32;
1198        let name_chars = name_str.chars().map(u32::from);
1199        let variants = &self.variants;
1200        let variant_count = self.variant_values.len() as u32;
1201        let variant_values = &self.variant_values;
1202        let variant_indices = (0..variant_count).collect::<Vec<_>>();
1203        let invalid = variant_count;
1204        let hole = variant_count + 1;
1205        let attrs = &self.rust_attrs;
1206
1207        let invalid_to_str_msg = format!(
1208            "Converting an invalid string enum ({}) back to a string is currently not supported",
1209            enum_name
1210        );
1211
1212        // A vector of EnumName::VariantName tokens for this enum
1213        let variant_paths: Vec<TokenStream> = self
1214            .variants
1215            .iter()
1216            .map(|v| quote!(#enum_name::#v).into_token_stream())
1217            .collect();
1218
1219        // Borrow variant_paths because we need to use it multiple times inside the quote! macro
1220        let variant_paths_ref = &variant_paths;
1221
1222        let wasm_bindgen = &self.wasm_bindgen;
1223
1224        (quote! {
1225            #(#attrs)*
1226            #[non_exhaustive]
1227            #[repr(u32)]
1228            #vis enum #enum_name {
1229                #(#variants = #variant_indices,)*
1230                #[automatically_derived]
1231                #[doc(hidden)]
1232                __Invalid
1233            }
1234
1235            #[automatically_derived]
1236            impl #enum_name {
1237                fn from_str(s: &str) -> Option<#enum_name> {
1238                    match s {
1239                        #(#variant_values => Some(#variant_paths_ref),)*
1240                        _ => None,
1241                    }
1242                }
1243
1244                fn to_str(&self) -> &'static str {
1245                    match self {
1246                        #(#variant_paths_ref => #variant_values,)*
1247                        #enum_name::__Invalid => panic!(#invalid_to_str_msg),
1248                    }
1249                }
1250
1251                #vis fn from_js_value(obj: &#wasm_bindgen::JsValue) -> Option<#enum_name> {
1252                    obj.as_string().and_then(|obj_str| Self::from_str(obj_str.as_str()))
1253                }
1254            }
1255
1256            #[automatically_derived]
1257            impl #wasm_bindgen::convert::IntoWasmAbi for #enum_name {
1258                type Abi = u32;
1259
1260                #[inline]
1261                fn into_abi(self) -> u32 {
1262                    self as u32
1263                }
1264            }
1265
1266            #[automatically_derived]
1267            impl #wasm_bindgen::convert::FromWasmAbi for #enum_name {
1268                type Abi = u32;
1269
1270                unsafe fn from_abi(val: u32) -> Self {
1271                    match val {
1272                        #(#variant_indices => #variant_paths_ref,)*
1273                        #invalid => #enum_name::__Invalid,
1274                        _ => unreachable!("The JS binding should only ever produce a valid value or the specific 'invalid' value"),
1275                    }
1276                }
1277            }
1278
1279            #[automatically_derived]
1280            impl #wasm_bindgen::convert::OptionFromWasmAbi for #enum_name {
1281                #[inline]
1282                fn is_none(val: &u32) -> bool { *val == #hole }
1283            }
1284
1285            #[automatically_derived]
1286            impl #wasm_bindgen::convert::OptionIntoWasmAbi for #enum_name {
1287                #[inline]
1288                fn none() -> Self::Abi { #hole }
1289            }
1290
1291            #[automatically_derived]
1292            impl #wasm_bindgen::describe::WasmDescribe for #enum_name {
1293                fn describe() {
1294                    use #wasm_bindgen::describe::*;
1295                    inform(STRING_ENUM);
1296                    inform(#name_len);
1297                    #(inform(#name_chars);)*
1298                    inform(#variant_count);
1299                }
1300            }
1301
1302            #[automatically_derived]
1303            impl #wasm_bindgen::__rt::core::convert::From<#enum_name> for
1304                #wasm_bindgen::JsValue
1305            {
1306                fn from(val: #enum_name) -> Self {
1307                    #wasm_bindgen::JsValue::from_str(val.to_str())
1308                }
1309            }
1310        })
1311        .to_tokens(tokens);
1312    }
1313}
1314
1315impl TryToTokens for ast::ImportFunction {
1316    fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
1317        let mut class_ty = None;
1318        let mut is_method = false;
1319        match self.kind {
1320            ast::ImportFunctionKind::Method {
1321                ref ty, ref kind, ..
1322            } => {
1323                if let ast::MethodKind::Operation(ast::Operation {
1324                    is_static: false, ..
1325                }) = kind
1326                {
1327                    is_method = true;
1328                }
1329                class_ty = Some(ty);
1330            }
1331            ast::ImportFunctionKind::Normal => {}
1332        }
1333        let vis = &self.function.rust_vis;
1334        let ret = match self.function.ret.as_ref().map(|ret| &ret.r#type) {
1335            Some(ty) => quote! { -> #ty },
1336            None => quote!(),
1337        };
1338
1339        let mut abi_argument_names = Vec::new();
1340        let mut abi_arguments = Vec::new();
1341        let mut arg_conversions = Vec::new();
1342        let mut arguments = Vec::new();
1343        let ret_ident = Ident::new("_ret", Span::call_site());
1344        let wasm_bindgen = &self.wasm_bindgen;
1345        let wasm_bindgen_futures = &self.wasm_bindgen_futures;
1346
1347        for (i, arg) in self.function.arguments.iter().enumerate() {
1348            let ty = &arg.pat_type.ty;
1349            let name = match &*arg.pat_type.pat {
1350                syn::Pat::Ident(syn::PatIdent {
1351                    by_ref: None,
1352                    ident,
1353                    subpat: None,
1354                    ..
1355                }) => ident.clone(),
1356                syn::Pat::Wild(_) => syn::Ident::new(&format!("__genarg_{}", i), Span::call_site()),
1357                _ => bail_span!(
1358                    arg.pat_type.pat,
1359                    "unsupported pattern in #[wasm_bindgen] imported function",
1360                ),
1361            };
1362
1363            let abi = quote! { <#ty as #wasm_bindgen::convert::IntoWasmAbi>::Abi };
1364            let (prim_args, prim_names) = splat(wasm_bindgen, &name, &abi);
1365            abi_arguments.extend(prim_args);
1366            abi_argument_names.extend(prim_names.iter().cloned());
1367
1368            let var = if i == 0 && is_method {
1369                quote! { self }
1370            } else {
1371                arguments.push(quote! { #name: #ty });
1372                quote! { #name }
1373            };
1374            arg_conversions.push(quote! {
1375                let #name = <#ty as #wasm_bindgen::convert::IntoWasmAbi>
1376                    ::into_abi(#var);
1377                let (#(#prim_names),*) = <#abi as #wasm_bindgen::convert::WasmAbi>::split(#name);
1378            });
1379        }
1380        let abi_ret;
1381        let mut convert_ret;
1382        match &self.js_ret {
1383            Some(syn::Type::Reference(_)) => {
1384                bail_span!(
1385                    self.js_ret,
1386                    "cannot return references in #[wasm_bindgen] imports yet"
1387                );
1388            }
1389            Some(ref ty) => {
1390                if self.function.r#async {
1391                    abi_ret = quote! {
1392                        #wasm_bindgen::convert::WasmRet<<#wasm_bindgen_futures::js_sys::Promise as #wasm_bindgen::convert::FromWasmAbi>::Abi>
1393                    };
1394                    let future = quote! {
1395                        #wasm_bindgen_futures::JsFuture::from(
1396                            <#wasm_bindgen_futures::js_sys::Promise as #wasm_bindgen::convert::FromWasmAbi>
1397                                ::from_abi(#ret_ident.join())
1398                        ).await
1399                    };
1400                    convert_ret = if self.catch {
1401                        quote! { Ok(#wasm_bindgen::JsCast::unchecked_from_js(#future?)) }
1402                    } else {
1403                        quote! { #wasm_bindgen::JsCast::unchecked_from_js(#future.expect("unexpected exception")) }
1404                    };
1405                } else {
1406                    abi_ret = quote! {
1407                        #wasm_bindgen::convert::WasmRet<<#ty as #wasm_bindgen::convert::FromWasmAbi>::Abi>
1408                    };
1409                    convert_ret = quote! {
1410                        <#ty as #wasm_bindgen::convert::FromWasmAbi>
1411                            ::from_abi(#ret_ident.join())
1412                    };
1413                }
1414            }
1415            None => {
1416                if self.function.r#async {
1417                    abi_ret = quote! {
1418                        #wasm_bindgen::convert::WasmRet<<#wasm_bindgen_futures::js_sys::Promise as #wasm_bindgen::convert::FromWasmAbi>::Abi>
1419                    };
1420                    let future = quote! {
1421                        #wasm_bindgen_futures::JsFuture::from(
1422                            <#wasm_bindgen_futures::js_sys::Promise as #wasm_bindgen::convert::FromWasmAbi>
1423                                ::from_abi(#ret_ident.join())
1424                        ).await
1425                    };
1426                    convert_ret = if self.catch {
1427                        quote! { #future?; Ok(()) }
1428                    } else {
1429                        quote! { #future.expect("uncaught exception"); }
1430                    };
1431                } else {
1432                    abi_ret = quote! { () };
1433                    convert_ret = quote! { () };
1434                }
1435            }
1436        }
1437
1438        let mut exceptional_ret = quote!();
1439        if self.catch && !self.function.r#async {
1440            convert_ret = quote! { Ok(#convert_ret) };
1441            exceptional_ret = quote! {
1442                #wasm_bindgen::__rt::take_last_exception()?;
1443            };
1444        }
1445
1446        let rust_name = &self.rust_name;
1447        let import_name = &self.shim;
1448        let attrs = &self.function.rust_attrs;
1449        let arguments = &arguments;
1450        let abi_arguments = &abi_arguments[..];
1451        let abi_argument_names = &abi_argument_names[..];
1452
1453        let doc = if self.doc_comment.is_empty() {
1454            quote! {}
1455        } else {
1456            let doc_comment = &self.doc_comment;
1457            quote! { #[doc = #doc_comment] }
1458        };
1459        let me = if is_method {
1460            quote! { &self, }
1461        } else {
1462            quote!()
1463        };
1464
1465        // Route any errors pointing to this imported function to the identifier
1466        // of the function we're imported from so we at least know what function
1467        // is causing issues.
1468        //
1469        // Note that this is where type errors like "doesn't implement
1470        // FromWasmAbi" or "doesn't implement IntoWasmAbi" currently get routed.
1471        // I suspect that's because they show up in the signature via trait
1472        // projections as types of arguments, and all that needs to typecheck
1473        // before the body can be typechecked. Due to rust-lang/rust#60980 (and
1474        // probably related issues) we can't really get a precise span.
1475        //
1476        // Ideally what we want is to point errors for particular types back to
1477        // the specific argument/type that generated the error, but it looks
1478        // like rustc itself doesn't do great in that regard so let's just do
1479        // the best we can in the meantime.
1480        let extern_fn = respan(
1481            extern_fn(
1482                import_name,
1483                attrs,
1484                abi_arguments,
1485                abi_argument_names,
1486                abi_ret,
1487            ),
1488            &self.rust_name,
1489        );
1490
1491        let maybe_unsafe = if self.function.r#unsafe {
1492            Some(quote! {unsafe})
1493        } else {
1494            None
1495        };
1496        let maybe_async = if self.function.r#async {
1497            Some(quote! {async})
1498        } else {
1499            None
1500        };
1501        let invocation = quote! {
1502            // This is due to `#[automatically_derived]` attribute cannot be
1503            // placed onto bare functions.
1504            #[allow(nonstandard_style)]
1505            #[allow(clippy::all, clippy::nursery, clippy::pedantic, clippy::restriction)]
1506            #(#attrs)*
1507            #doc
1508            #vis #maybe_async #maybe_unsafe fn #rust_name(#me #(#arguments),*) #ret {
1509                #extern_fn
1510
1511                unsafe {
1512                    let #ret_ident = {
1513                        #(#arg_conversions)*
1514                        #import_name(#(#abi_argument_names),*)
1515                    };
1516                    #exceptional_ret
1517                    #convert_ret
1518                }
1519            }
1520        };
1521
1522        if let Some(class) = class_ty {
1523            (quote! {
1524                #[automatically_derived]
1525                impl #class {
1526                    #invocation
1527                }
1528            })
1529            .to_tokens(tokens);
1530        } else {
1531            invocation.to_tokens(tokens);
1532        }
1533
1534        Ok(())
1535    }
1536}
1537
1538// See comment above in ast::Export for what's going on here.
1539struct DescribeImport<'a> {
1540    kind: &'a ast::ImportKind,
1541    wasm_bindgen: &'a syn::Path,
1542}
1543
1544impl ToTokens for DescribeImport<'_> {
1545    fn to_tokens(&self, tokens: &mut TokenStream) {
1546        let f = match *self.kind {
1547            ast::ImportKind::Function(ref f) => f,
1548            ast::ImportKind::Static(_) => return,
1549            ast::ImportKind::String(_) => return,
1550            ast::ImportKind::Type(_) => return,
1551            ast::ImportKind::Enum(_) => return,
1552        };
1553        let argtys = f.function.arguments.iter().map(|arg| &arg.pat_type.ty);
1554        let nargs = f.function.arguments.len() as u32;
1555        let inform_ret = match &f.js_ret {
1556            Some(ref t) => quote! { <#t as WasmDescribe>::describe(); },
1557            // async functions always return a JsValue, even if they say to return ()
1558            None if f.function.r#async => quote! { <JsValue as WasmDescribe>::describe(); },
1559            None => quote! { <() as WasmDescribe>::describe(); },
1560        };
1561
1562        Descriptor {
1563            ident: &f.shim,
1564            inner: quote! {
1565                inform(FUNCTION);
1566                inform(0);
1567                inform(#nargs);
1568                #(<#argtys as WasmDescribe>::describe();)*
1569                #inform_ret
1570                #inform_ret
1571            },
1572            attrs: f.function.rust_attrs.clone(),
1573            wasm_bindgen: self.wasm_bindgen,
1574        }
1575        .to_tokens(tokens);
1576    }
1577}
1578
1579impl ToTokens for ast::Enum {
1580    fn to_tokens(&self, into: &mut TokenStream) {
1581        let enum_name = &self.rust_name;
1582        let name_str = self.js_name.to_string();
1583        let name_len = name_str.len() as u32;
1584        let name_chars = name_str.chars().map(|c| c as u32);
1585        let hole = &self.hole;
1586        let underlying = if self.signed {
1587            quote! { i32 }
1588        } else {
1589            quote! { u32 }
1590        };
1591        let cast_clauses = self.variants.iter().map(|variant| {
1592            let variant_name = &variant.name;
1593            quote! {
1594                if js == #enum_name::#variant_name as #underlying {
1595                    #enum_name::#variant_name
1596                }
1597            }
1598        });
1599        let try_from_cast_clauses = cast_clauses.clone();
1600        let wasm_bindgen = &self.wasm_bindgen;
1601        (quote! {
1602            #[automatically_derived]
1603            impl #wasm_bindgen::convert::IntoWasmAbi for #enum_name {
1604                type Abi = #underlying;
1605
1606                #[inline]
1607                fn into_abi(self) -> #underlying {
1608                    self as #underlying
1609                }
1610            }
1611
1612            #[automatically_derived]
1613            impl #wasm_bindgen::convert::FromWasmAbi for #enum_name {
1614                type Abi = #underlying;
1615
1616                #[inline]
1617                unsafe fn from_abi(js: #underlying) -> Self {
1618                    #(#cast_clauses else)* {
1619                        #wasm_bindgen::throw_str("invalid enum value passed")
1620                    }
1621                }
1622            }
1623
1624            #[automatically_derived]
1625            impl #wasm_bindgen::convert::OptionFromWasmAbi for #enum_name {
1626                #[inline]
1627                fn is_none(val: &Self::Abi) -> bool { *val == #hole as #underlying }
1628            }
1629
1630            #[automatically_derived]
1631            impl #wasm_bindgen::convert::OptionIntoWasmAbi for #enum_name {
1632                #[inline]
1633                fn none() -> Self::Abi { #hole as #underlying }
1634            }
1635
1636            #[automatically_derived]
1637            impl #wasm_bindgen::describe::WasmDescribe for #enum_name {
1638                fn describe() {
1639                    use #wasm_bindgen::describe::*;
1640                    inform(ENUM);
1641                    inform(#name_len);
1642                    #(inform(#name_chars);)*
1643                    inform(#hole);
1644                }
1645            }
1646
1647            #[automatically_derived]
1648            impl #wasm_bindgen::__rt::core::convert::From<#enum_name> for
1649                #wasm_bindgen::JsValue
1650            {
1651                fn from(value: #enum_name) -> Self {
1652                    #wasm_bindgen::JsValue::from_f64((value as #underlying).into())
1653                }
1654            }
1655
1656            #[automatically_derived]
1657            impl #wasm_bindgen::convert::TryFromJsValue for #enum_name {
1658                type Error = #wasm_bindgen::JsValue;
1659
1660                fn try_from_js_value(value: #wasm_bindgen::JsValue)
1661                    -> #wasm_bindgen::__rt::core::result::Result<Self, <#enum_name as #wasm_bindgen::convert::TryFromJsValue>::Error> {
1662                    use #wasm_bindgen::__rt::core::convert::TryFrom;
1663                    let js = f64::try_from(&value)? as #underlying;
1664
1665                    #wasm_bindgen::__rt::core::result::Result::Ok(
1666                        #(#try_from_cast_clauses else)* {
1667                            return #wasm_bindgen::__rt::core::result::Result::Err(value)
1668                        }
1669                    )
1670                }
1671            }
1672
1673            #[automatically_derived]
1674            impl #wasm_bindgen::describe::WasmDescribeVector for #enum_name {
1675                fn describe_vector() {
1676                    use #wasm_bindgen::describe::*;
1677                    inform(VECTOR);
1678                    <#wasm_bindgen::JsValue as #wasm_bindgen::describe::WasmDescribe>::describe();
1679                }
1680            }
1681
1682            #[automatically_derived]
1683            impl #wasm_bindgen::convert::VectorIntoWasmAbi for #enum_name {
1684                type Abi = <
1685                    #wasm_bindgen::__rt::alloc::boxed::Box<[#wasm_bindgen::JsValue]>
1686                    as #wasm_bindgen::convert::IntoWasmAbi
1687                >::Abi;
1688
1689                fn vector_into_abi(
1690                    vector: #wasm_bindgen::__rt::alloc::boxed::Box<[#enum_name]>
1691                ) -> Self::Abi {
1692                    #wasm_bindgen::convert::js_value_vector_into_abi(vector)
1693                }
1694            }
1695
1696            #[automatically_derived]
1697            impl #wasm_bindgen::convert::VectorFromWasmAbi for #enum_name {
1698                type Abi = <
1699                    #wasm_bindgen::__rt::alloc::boxed::Box<[#wasm_bindgen::JsValue]>
1700                    as #wasm_bindgen::convert::FromWasmAbi
1701                >::Abi;
1702
1703                unsafe fn vector_from_abi(
1704                    js: Self::Abi
1705                ) -> #wasm_bindgen::__rt::alloc::boxed::Box<[#enum_name]> {
1706                    #wasm_bindgen::convert::js_value_vector_from_abi(js)
1707                }
1708            }
1709        })
1710        .to_tokens(into);
1711    }
1712}
1713
1714impl ToTokens for ast::ImportStatic {
1715    fn to_tokens(&self, into: &mut TokenStream) {
1716        let ty = &self.ty;
1717
1718        if let Some(thread_local) = self.thread_local {
1719            thread_local_import(
1720                &self.vis,
1721                &self.rust_name,
1722                &self.wasm_bindgen,
1723                ty,
1724                ty,
1725                &self.shim,
1726                thread_local,
1727            )
1728            .to_tokens(into)
1729        } else {
1730            let vis = &self.vis;
1731            let name = &self.rust_name;
1732            let wasm_bindgen = &self.wasm_bindgen;
1733            let ty = &self.ty;
1734            let shim_name = &self.shim;
1735            let init = static_init(wasm_bindgen, ty, shim_name);
1736
1737            into.extend(quote! {
1738                #[automatically_derived]
1739                #[deprecated = "use with `#[wasm_bindgen(thread_local_v2)]` instead"]
1740            });
1741            into.extend(
1742                quote_spanned! { name.span() => #vis static #name: #wasm_bindgen::JsStatic<#ty> = {
1743                        fn init() -> #ty {
1744                            #init
1745                        }
1746                        #wasm_bindgen::__rt::std::thread_local!(static _VAL: #ty = init(););
1747                        #wasm_bindgen::JsStatic {
1748                            __inner: &_VAL,
1749                        }
1750                    };
1751                },
1752            );
1753        }
1754
1755        Descriptor {
1756            ident: &self.shim,
1757            inner: quote! {
1758                <#ty as WasmDescribe>::describe();
1759            },
1760            attrs: vec![],
1761            wasm_bindgen: &self.wasm_bindgen,
1762        }
1763        .to_tokens(into);
1764    }
1765}
1766
1767impl ToTokens for ast::ImportString {
1768    fn to_tokens(&self, into: &mut TokenStream) {
1769        let js_sys = &self.js_sys;
1770        let actual_ty: syn::Type = parse_quote!(#js_sys::JsString);
1771
1772        thread_local_import(
1773            &self.vis,
1774            &self.rust_name,
1775            &self.wasm_bindgen,
1776            &actual_ty,
1777            &self.ty,
1778            &self.shim,
1779            self.thread_local,
1780        )
1781        .to_tokens(into);
1782    }
1783}
1784
1785fn thread_local_import(
1786    vis: &syn::Visibility,
1787    name: &Ident,
1788    wasm_bindgen: &syn::Path,
1789    actual_ty: &syn::Type,
1790    ty: &syn::Type,
1791    shim_name: &Ident,
1792    thread_local: ast::ThreadLocal,
1793) -> TokenStream {
1794    let init = static_init(wasm_bindgen, ty, shim_name);
1795
1796    match thread_local {
1797        ast::ThreadLocal::V1 => quote! {
1798            #wasm_bindgen::__rt::std::thread_local! {
1799                #[automatically_derived]
1800                #[deprecated = "use with `#[wasm_bindgen(thread_local_v2)]` instead"]
1801                #vis static #name: #actual_ty = {
1802                    #init
1803                };
1804            }
1805        },
1806        ast::ThreadLocal::V2 => {
1807            quote! {
1808                #vis static #name: #wasm_bindgen::JsThreadLocal<#actual_ty> = {
1809                    fn init() -> #actual_ty {
1810                        #init
1811                    }
1812                    #wasm_bindgen::__wbindgen_thread_local!(#wasm_bindgen, #actual_ty)
1813                };
1814            }
1815        }
1816    }
1817}
1818
1819fn static_init(wasm_bindgen: &syn::Path, ty: &syn::Type, shim_name: &Ident) -> TokenStream {
1820    let abi_ret = quote! {
1821        #wasm_bindgen::convert::WasmRet<<#ty as #wasm_bindgen::convert::FromWasmAbi>::Abi>
1822    };
1823    quote! {
1824        #[link(wasm_import_module = "__wbindgen_placeholder__")]
1825        #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
1826        extern "C" {
1827            fn #shim_name() -> #abi_ret;
1828        }
1829
1830        #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
1831        unsafe fn #shim_name() -> #abi_ret {
1832            panic!("cannot access imported statics on non-wasm targets")
1833        }
1834
1835        unsafe {
1836            <#ty as #wasm_bindgen::convert::FromWasmAbi>::from_abi(#shim_name().join())
1837        }
1838    }
1839}
1840
1841/// Emits the necessary glue tokens for "descriptor", generating an appropriate
1842/// symbol name as well as attributes around the descriptor function itself.
1843struct Descriptor<'a, T> {
1844    ident: &'a Ident,
1845    inner: T,
1846    attrs: Vec<syn::Attribute>,
1847    wasm_bindgen: &'a syn::Path,
1848}
1849
1850impl<T: ToTokens> ToTokens for Descriptor<'_, T> {
1851    fn to_tokens(&self, tokens: &mut TokenStream) {
1852        // It's possible for the same descriptor to be emitted in two different
1853        // modules (aka a value imported twice in a crate, each in a separate
1854        // module). In this case no need to emit duplicate descriptors (which
1855        // leads to duplicate symbol errors), instead just emit one.
1856        //
1857        // It's up to the descriptors themselves to ensure they have unique
1858        // names for unique items imported, currently done via `ShortHash` and
1859        // hashing appropriate data into the symbol name.
1860        thread_local! {
1861            static DESCRIPTORS_EMITTED: RefCell<HashSet<String>> = RefCell::default();
1862        }
1863
1864        let ident = self.ident;
1865
1866        if !DESCRIPTORS_EMITTED.with(|list| list.borrow_mut().insert(ident.to_string())) {
1867            return;
1868        }
1869
1870        let name = Ident::new(&format!("__wbindgen_describe_{}", ident), ident.span());
1871        let inner = &self.inner;
1872        let attrs = &self.attrs;
1873        let wasm_bindgen = &self.wasm_bindgen;
1874        (quote! {
1875            #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
1876            #[automatically_derived]
1877            const _: () = {
1878                #wasm_bindgen::__wbindgen_coverage! {
1879                #(#attrs)*
1880                #[no_mangle]
1881                #[doc(hidden)]
1882                pub extern "C" fn #name() {
1883                    use #wasm_bindgen::describe::*;
1884                    // See definition of `link_mem_intrinsics` for what this is doing
1885                    #wasm_bindgen::__rt::link_mem_intrinsics();
1886                    #inner
1887                }
1888                }
1889            };
1890        })
1891        .to_tokens(tokens);
1892    }
1893}
1894
1895fn extern_fn(
1896    import_name: &Ident,
1897    attrs: &[syn::Attribute],
1898    abi_arguments: &[TokenStream],
1899    abi_argument_names: &[Ident],
1900    abi_ret: TokenStream,
1901) -> TokenStream {
1902    quote! {
1903        #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
1904        #(#attrs)*
1905        #[link(wasm_import_module = "__wbindgen_placeholder__")]
1906        extern "C" {
1907            fn #import_name(#(#abi_arguments),*) -> #abi_ret;
1908        }
1909
1910        #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
1911        unsafe fn #import_name(#(#abi_arguments),*) -> #abi_ret {
1912            #(
1913                drop(#abi_argument_names);
1914            )*
1915            panic!("cannot call wasm-bindgen imported functions on \
1916                    non-wasm targets");
1917        }
1918    }
1919}
1920
1921/// Splats an argument with the given name and ABI type into 4 arguments, one
1922/// for each primitive that the ABI type splits into.
1923///
1924/// Returns an `(args, names)` pair, where `args` is the list of arguments to
1925/// be inserted into the function signature, and `names` is a list of the names
1926/// of those arguments.
1927fn splat(
1928    wasm_bindgen: &syn::Path,
1929    name: &Ident,
1930    abi: &TokenStream,
1931) -> (Vec<TokenStream>, Vec<Ident>) {
1932    let mut args = Vec::new();
1933    let mut names = Vec::new();
1934
1935    for n in 1_u32..=4 {
1936        let arg_name = format_ident!("{}_{}", name, n);
1937        let prim_name = format_ident!("Prim{}", n);
1938        args.push(quote! {
1939            #arg_name: <#abi as #wasm_bindgen::convert::WasmAbi>::#prim_name
1940        });
1941        names.push(arg_name);
1942    }
1943
1944    (args, names)
1945}
1946
1947/// Converts `span` into a stream of tokens, and attempts to ensure that `input`
1948/// has all the appropriate span information so errors in it point to `span`.
1949fn respan(input: TokenStream, span: &dyn ToTokens) -> TokenStream {
1950    let mut first_span = Span::call_site();
1951    let mut last_span = Span::call_site();
1952    let mut spans = TokenStream::new();
1953    span.to_tokens(&mut spans);
1954
1955    for (i, token) in spans.into_iter().enumerate() {
1956        if i == 0 {
1957            first_span = Span::call_site().located_at(token.span());
1958        }
1959        last_span = Span::call_site().located_at(token.span());
1960    }
1961
1962    let mut new_tokens = Vec::new();
1963    for (i, mut token) in input.into_iter().enumerate() {
1964        if i == 0 {
1965            token.set_span(first_span);
1966        } else {
1967            token.set_span(last_span);
1968        }
1969        new_tokens.push(token);
1970    }
1971    new_tokens.into_iter().collect()
1972}