Skip to main content

wit_bindgen_go/
lib.rs

1use anyhow::Result;
2use heck::{ToLowerCamelCase as _, ToSnakeCase as _, ToUpperCamelCase as _};
3use std::borrow::Cow;
4use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, hash_map};
5use std::fmt;
6use std::fmt::Write as _;
7use std::io::{self, Write as _};
8use std::iter;
9use std::mem;
10use std::process::Command;
11use std::str::FromStr;
12use std::thread;
13use wit_bindgen_core::abi::{
14    self, AbiVariant, Bindgen, Bitcast, FlatTypes, Instruction, LiftLower, WasmType,
15};
16use wit_bindgen_core::wit_parser::{
17    Alignment, ArchitectureSize, Docs, Enum, Flags, FlagsRepr, Function, FunctionKind, Handle, Int,
18    InterfaceId, Package, PackageName, Param, Record, Resolve, Result_, SizeAlign, Tuple, Type,
19    TypeDefKind, TypeId, TypeOwner, Variant, WorldId, WorldKey,
20};
21use wit_bindgen_core::{
22    AsyncFilterSet, Direction, Files, InterfaceGenerator as _, Ns, WorldGenerator, uwriteln,
23};
24
25const MAX_FLAT_PARAMS: usize = 16;
26
27const POINTER_SIZE_EXPRESSION: &str = "4";
28const VARIANT_PAYLOAD_NAME: &str = "payload";
29const ITER_BASE_POINTER: &str = "base";
30const ITER_ELEMENT: &str = "element";
31const IMPORT_RETURN_AREA: &str = "returnArea";
32const EXPORT_RETURN_AREA: &str = "exportReturnArea";
33const SYNC_EXPORT_PINNER: &str = "syncExportPinner";
34const PINNER: &str = "pinner";
35
36/// Adds the shared package repository prefix to a package name.
37fn remote_pkg(name: &str) -> String {
38    let prefix = match name {
39        "types" => "witTypes",
40        "async" => "witAsync",
41        "runtime" => "witRuntime",
42        _ => unimplemented!(),
43    };
44    format!(r#"{prefix} "go.bytecodealliance.org/pkg/wit/{name}""#)
45}
46
47/// The version of github.com/bytecodealliance/go-pkg that's being used
48const REMOTE_PKG_VERSION: &str = "v0.2.1";
49
50/// If a user specifies the `pkg_name` flag, the required version for the
51/// shared remote package isn't recorded. This enables downstream users to retrieve the version programmatically.
52pub fn remote_pkg_version() -> String {
53    format!("go.bytecodealliance.org/pkg {REMOTE_PKG_VERSION}")
54}
55
56#[derive(Default, Debug, Copy, Clone)]
57pub enum Format {
58    #[default]
59    True,
60    False,
61}
62
63impl fmt::Display for Format {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        write!(
66            f,
67            "{}",
68            match self {
69                Self::True => "true",
70                Self::False => "false",
71            }
72        )
73    }
74}
75
76impl FromStr for Format {
77    type Err = String;
78
79    fn from_str(s: &str) -> Result<Format, String> {
80        match s {
81            "true" => Ok(Format::True),
82            "false" => Ok(Format::False),
83            _ => Err(format!("expected `true` or `false`; got `{s}`")),
84        }
85    }
86}
87
88#[derive(Default, Debug, Clone)]
89#[cfg_attr(feature = "clap", derive(clap::Parser))]
90pub struct Opts {
91    /// Whether or not `gofmt` should be used (if present) to format generated
92    /// code.
93    #[cfg_attr(
94        feature = "clap",
95        arg(
96            long,
97            default_value = "true",
98            default_missing_value = "true",
99            num_args = 0..=1,
100            require_equals = true,
101        )
102    )]
103    pub format: Format,
104
105    #[cfg_attr(feature = "clap", clap(flatten))]
106    pub async_: AsyncFilterSet,
107
108    /// If true, generate stub functions for any exported functions and/or
109    /// resources.
110    #[cfg_attr(feature = "clap", clap(long))]
111    pub generate_stubs: bool,
112
113    /// If specified, organize the bindings into a package for use as a library;
114    /// otherwise (if `None`), the bindings will be organized for use as a
115    /// standalone executable.
116    #[cfg_attr(feature = "clap", clap(long))]
117    pub pkg_name: Option<String>,
118
119    /// When `--pkg-name` is specified, optionally specify a different package
120    /// for exports.
121    ///
122    /// This allows you to put the exports and imports in separate packages when
123    /// building a library.  If only `--pkg-name` is specified, this will
124    /// default to that value.
125    #[cfg_attr(feature = "clap", clap(long, requires = "pkg_name"))]
126    pub export_pkg_name: Option<String>,
127
128    /// Print the version of the remote package being used for the shared WIT types.
129    ///
130    /// Must be specified in addition to the `pkg-name` flag.
131    #[cfg_attr(feature = "clap", clap(long))]
132    pub print_remote_pkg_version: bool,
133
134    /// When generating Go package names, include the WIT package version even
135    /// if only one version of that package is referenced by the specified
136    /// world.
137    ///
138    /// By default, the version will only be included in the name if the world
139    /// references more than one version of the WIT package.
140    #[cfg_attr(feature = "clap", clap(long))]
141    pub include_versions: bool,
142}
143
144impl Opts {
145    pub fn build(&self) -> Box<dyn WorldGenerator> {
146        Box::new(Go {
147            opts: self.clone(),
148            ..Go::default()
149        })
150    }
151}
152
153#[derive(Default)]
154struct InterfaceData {
155    code: String,
156    imports: BTreeSet<String>,
157    need_unsafe: bool,
158    need_runtime: bool,
159    need_math: bool,
160}
161
162impl InterfaceData {
163    fn extend(&mut self, data: InterfaceData) {
164        self.code.push_str(&data.code);
165        self.imports.extend(data.imports);
166        self.need_unsafe |= data.need_unsafe;
167        self.need_runtime |= data.need_runtime;
168        self.need_math |= data.need_math;
169    }
170
171    fn imports(&self) -> String {
172        self.imports
173            .iter()
174            .map(|s| s.to_string())
175            .chain(self.need_unsafe.then(|| r#""unsafe""#.into()))
176            .chain(self.need_runtime.then(|| r#""runtime""#.into()))
177            .chain(self.need_math.then(|| r#""math""#.into()))
178            .collect::<Vec<_>>()
179            .join("\n")
180    }
181
182    fn from_generator_and_code(generator: FunctionGenerator<'_>, code: String) -> Self {
183        Self {
184            code,
185            imports: generator.imports,
186            need_unsafe: generator.need_unsafe,
187            need_runtime: generator.need_pinner,
188            need_math: generator.need_math,
189        }
190    }
191}
192
193impl From<InterfaceGenerator<'_>> for InterfaceData {
194    fn from(generator: InterfaceGenerator<'_>) -> Self {
195        Self {
196            code: generator.src,
197            imports: generator.imports,
198            need_unsafe: generator.need_unsafe,
199            need_runtime: generator.need_runtime,
200            need_math: false,
201        }
202    }
203}
204
205#[derive(Default)]
206struct Go {
207    opts: Opts,
208    src: String,
209    sizes: SizeAlign,
210    return_area_size: ArchitectureSize,
211    return_area_align: Alignment,
212    imports: BTreeSet<String>,
213    tuples: BTreeSet<usize>,
214    need_option: bool,
215    need_result: bool,
216    need_math: bool,
217    need_unit: bool,
218    need_future: bool,
219    need_stream: bool,
220    need_unsafe: bool,
221    interface_names: HashMap<InterfaceId, WorldKey>,
222    interfaces: BTreeMap<String, InterfaceData>,
223    export_interfaces: BTreeMap<String, InterfaceData>,
224    types: HashSet<TypeId>,
225    resources: HashMap<TypeId, Direction>,
226    futures_and_streams: HashMap<(TypeId, bool), Option<WorldKey>>,
227}
228
229impl Go {
230    /// Adds the bindings module prefix to a package name.
231    fn mod_pkg(&self, for_export: bool, name: &str) -> String {
232        let prefix = for_export
233            .then_some(())
234            .and(self.opts.export_pkg_name.as_deref())
235            .or(self.opts.pkg_name.as_deref())
236            .unwrap_or("wit_component");
237        format!(r#""{prefix}/{name}""#)
238    }
239
240    fn package_for_owner(
241        &mut self,
242        resolve: &Resolve,
243        owner: Option<&WorldKey>,
244        id: TypeId,
245        local: Option<&WorldKey>,
246        in_import: bool,
247        imports: &mut BTreeSet<String>,
248    ) -> String {
249        let exported = self.has_exported_resource(resolve, Type::Id(id));
250
251        if local == owner && (exported ^ in_import) {
252            String::new()
253        } else {
254            let package = self.interface_name(resolve, owner);
255            let package = if exported {
256                format!("export_{package}")
257            } else {
258                package
259            };
260            let prefix = format!("{package}.");
261            imports.insert(self.mod_pkg(exported, &package));
262            prefix
263        }
264    }
265
266    fn package(
267        &mut self,
268        resolve: &Resolve,
269        id: TypeId,
270        local: Option<&WorldKey>,
271        in_import: bool,
272        imports: &mut BTreeSet<String>,
273    ) -> String {
274        let ty = &resolve.types[id];
275        let owner = match ty.owner {
276            TypeOwner::World(_) => None,
277            TypeOwner::Interface(id) => Some(
278                self.interface_names
279                    .get(&id)
280                    .cloned()
281                    .unwrap_or(WorldKey::Interface(id)),
282            ),
283            TypeOwner::None => unreachable!(),
284        };
285
286        self.package_for_owner(resolve, owner.as_ref(), id, local, in_import, imports)
287    }
288
289    fn type_name(
290        &mut self,
291        resolve: &Resolve,
292        ty: Type,
293        local: Option<&WorldKey>,
294        in_import: bool,
295        imports: &mut BTreeSet<String>,
296    ) -> String {
297        match ty {
298            Type::Bool => "bool".into(),
299            Type::U8 => "uint8".into(),
300            Type::S8 => "int8".into(),
301            Type::U16 => "uint16".into(),
302            Type::S16 => "int16".into(),
303            Type::U32 => "uint32".into(),
304            Type::S32 => "int32".into(),
305            Type::U64 => "uint64".into(),
306            Type::S64 => "int64".into(),
307            Type::F32 => "float32".into(),
308            Type::F64 => "float64".into(),
309            Type::Char => "rune".into(),
310            Type::String => "string".into(),
311            Type::Id(id) => {
312                let ty = &resolve.types[id];
313                match &ty.kind {
314                    TypeDefKind::Record(_)
315                    | TypeDefKind::Flags(_)
316                    | TypeDefKind::Variant(_)
317                    | TypeDefKind::Enum(_)
318                    | TypeDefKind::Resource => {
319                        let package = self.package(resolve, id, local, in_import, imports);
320                        let name = ty.name.as_ref().unwrap().to_upper_camel_case();
321                        format!("{package}{name}")
322                    }
323                    TypeDefKind::Handle(Handle::Own(ty) | Handle::Borrow(ty)) => {
324                        let name =
325                            self.type_name(resolve, Type::Id(*ty), local, in_import, imports);
326                        format!("*{name}")
327                    }
328                    TypeDefKind::Option(ty) => {
329                        imports.insert(remote_pkg("types"));
330                        let ty = self.type_name(resolve, *ty, local, in_import, imports);
331                        format!("witTypes.Option[{ty}]")
332                    }
333                    TypeDefKind::List(ty) => {
334                        let ty = self.type_name(resolve, *ty, local, in_import, imports);
335                        format!("[]{ty}")
336                    }
337                    TypeDefKind::Result(result) => {
338                        imports.insert(remote_pkg("types"));
339                        let ok_type = result
340                            .ok
341                            .map(|ty| self.type_name(resolve, ty, local, in_import, imports))
342                            .unwrap_or_else(|| {
343                                self.need_unit = true;
344                                "witTypes.Unit".into()
345                            });
346                        let err_type = result
347                            .err
348                            .map(|ty| self.type_name(resolve, ty, local, in_import, imports))
349                            .unwrap_or_else(|| {
350                                self.need_unit = true;
351                                "witTypes.Unit".into()
352                            });
353                        format!("witTypes.Result[{ok_type}, {err_type}]")
354                    }
355                    TypeDefKind::Tuple(tuple) => {
356                        imports.insert(remote_pkg("types"));
357                        let count = tuple.types.len();
358                        if count > 16 {
359                            todo!(
360                                "tuples can not have a capacity greater than 16: {:?}",
361                                ty.kind
362                            )
363                        }
364                        self.tuples.insert(count);
365                        let types = tuple
366                            .types
367                            .iter()
368                            .map(|ty| self.type_name(resolve, *ty, local, in_import, imports))
369                            .collect::<Vec<_>>()
370                            .join(", ");
371                        format!("witTypes.Tuple{count}[{types}]")
372                    }
373                    TypeDefKind::Future(ty) => {
374                        self.need_future = true;
375                        imports.insert(remote_pkg("types"));
376                        let ty = ty
377                            .map(|ty| self.type_name(resolve, ty, local, in_import, imports))
378                            .unwrap_or_else(|| {
379                                self.need_unit = true;
380                                "witTypes.Unit".into()
381                            });
382                        format!("*witTypes.FutureReader[{ty}]")
383                    }
384                    TypeDefKind::Stream(ty) => {
385                        self.need_stream = true;
386                        imports.insert(remote_pkg("types"));
387                        let ty = ty
388                            .map(|ty| self.type_name(resolve, ty, local, in_import, imports))
389                            .unwrap_or_else(|| {
390                                self.need_unit = true;
391                                "witTypes.Unit".into()
392                            });
393                        format!("*witTypes.StreamReader[{ty}]")
394                    }
395                    TypeDefKind::Type(ty) => {
396                        self.type_name(resolve, *ty, local, in_import, imports)
397                    }
398                    TypeDefKind::Map(key, value) => {
399                        let key = self.type_name(resolve, *key, local, in_import, imports);
400                        let value = self.type_name(resolve, *value, local, in_import, imports);
401                        format!("map[{key}]{value}")
402                    }
403                    _ => todo!("{:?}", ty.kind),
404                }
405            }
406            _ => todo!("{ty:?}"),
407        }
408    }
409
410    #[expect(clippy::too_many_arguments, reason = "required context codegen")]
411    fn future_or_stream(
412        &mut self,
413        resolve: &Resolve,
414        ty: TypeId,
415        index: usize,
416        in_import: bool,
417        imported_type: bool,
418        interface: Option<&WorldKey>,
419        func_name: &str,
420    ) -> InterfaceData {
421        let prefix = if in_import { "" } else { "[export]" };
422
423        let module = format!(
424            "{prefix}{}",
425            interface
426                .as_ref()
427                .map(|name| resolve.name_world_key(name))
428                .unwrap_or_else(|| "$root".into())
429        );
430
431        let (payload_ty, kind, count) = match &resolve.types[ty].kind {
432            TypeDefKind::Future(ty) => (*ty, "future", ""),
433            TypeDefKind::Stream(ty) => (*ty, "stream", ", count uint32"),
434            _ => unreachable!(),
435        };
436
437        let upper_kind = kind.to_upper_camel_case();
438
439        let mut data = InterfaceData {
440            need_unsafe: true,
441            ..InterfaceData::default()
442        };
443        data.imports.insert(remote_pkg("types"));
444
445        let (payload, snake) = if let Some(ty) = payload_ty {
446            (
447                self.type_name(resolve, ty, interface, imported_type, &mut data.imports),
448                self.mangle_name(resolve, ty, interface),
449            )
450        } else {
451            self.need_unit = true;
452            ("witTypes.Unit".into(), "unit".into())
453        };
454        let camel = snake.to_upper_camel_case();
455
456        let abi = self.sizes.record(payload_ty.as_ref());
457        let size = abi.size.format(POINTER_SIZE_EXPRESSION);
458        let align = abi.align.format(POINTER_SIZE_EXPRESSION);
459
460        // TODO: Skip lifting/lowering other types that can be used directly in
461        // their canonical form:
462        let (lift, lift_name, lower, lower_name) = match payload_ty {
463            None => (
464                format!(
465                    "func wasm_{kind}_lift_{snake}(src unsafe.Pointer) {payload} {{
466	return witTypes.Unit{{}}
467}}
468"
469                ),
470                format!("wasm_{kind}_lift_{snake}"),
471                String::new(),
472                "nil".to_string(),
473            ),
474            Some(Type::U8 | Type::S8) => (
475                String::new(),
476                "nil".to_string(),
477                String::new(),
478                "nil".to_string(),
479            ),
480            Some(ty) => {
481                data.need_runtime = true;
482
483                let mut generator = FunctionGenerator::new(
484                    self,
485                    None,
486                    None,
487                    interface,
488                    "INVALID",
489                    Vec::new(),
490                    false,
491                    imported_type,
492                );
493                generator.collect_lifters = true;
494
495                let lift_result =
496                    abi::lift_from_memory(resolve, &mut generator, "src".to_string(), &ty);
497                let lift = mem::take(&mut generator.src);
498
499                abi::lower_to_memory(
500                    resolve,
501                    &mut generator,
502                    "dst".to_string(),
503                    "value".to_string(),
504                    &ty,
505                );
506
507                let lifter_count = generator.lifter_count;
508                let (prefix, suffix) = if lifter_count > 0 {
509                    (
510                        format!("lifters := make([]func(), 0, {lifter_count})\n"),
511                        "\nreturn func() {
512        for _, lifter := range lifters {
513                lifter()
514        }
515}",
516                    )
517                } else {
518                    (String::new(), "\nreturn func() {}")
519                };
520
521                let lower = mem::take(&mut generator.src);
522                data.extend(InterfaceData::from_generator_and_code(
523                    generator,
524                    String::new(),
525                ));
526
527                (
528                    format!(
529                        "func wasm_{kind}_lift_{snake}(src unsafe.Pointer) {payload} {{
530        {lift}
531	return {lift_result}
532}}
533"
534                    ),
535                    format!("wasm_{kind}_lift_{snake}"),
536                    format!(
537                        "func wasm_{kind}_lower_{snake}(
538        pinner *runtime.Pinner,
539        value {payload},
540        dst unsafe.Pointer,
541) func() {{
542        {prefix}{lower}{suffix}
543}}
544"
545                    ),
546                    format!("wasm_{kind}_lower_{snake}"),
547                )
548            }
549        };
550
551        data.code = format!(
552            r#"
553//go:wasmimport {module} [{kind}-new-{index}]{func_name}
554func wasm_{kind}_new_{snake}() uint64
555
556//go:wasmimport {module} [async-lower][{kind}-read-{index}]{func_name}
557func wasm_{kind}_read_{snake}(handle int32, item unsafe.Pointer{count}) uint32
558
559//go:wasmimport {module} [async-lower][{kind}-write-{index}]{func_name}
560func wasm_{kind}_write_{snake}(handle int32, item unsafe.Pointer{count}) uint32
561
562//go:wasmimport {module} [{kind}-drop-readable-{index}]{func_name}
563func wasm_{kind}_drop_readable_{snake}(handle int32)
564
565//go:wasmimport {module} [{kind}-drop-writable-{index}]{func_name}
566func wasm_{kind}_drop_writable_{snake}(handle int32)
567
568{lift}
569
570{lower}
571
572var wasm_{kind}_vtable_{snake} = witTypes.{upper_kind}Vtable[{payload}]{{
573	{size},
574	{align},
575	wasm_{kind}_read_{snake},
576	wasm_{kind}_write_{snake},
577	nil,
578	nil,
579	wasm_{kind}_drop_readable_{snake},
580	wasm_{kind}_drop_writable_{snake},
581	{lift_name},
582	{lower_name},
583}}
584
585func Make{upper_kind}{camel}() (*witTypes.{upper_kind}Writer[{payload}], *witTypes.{upper_kind}Reader[{payload}]) {{
586	pair := wasm_{kind}_new_{snake}()
587	return witTypes.Make{upper_kind}Writer[{payload}](&wasm_{kind}_vtable_{snake}, int32(pair >> 32)),
588		witTypes.Make{upper_kind}Reader[{payload}](&wasm_{kind}_vtable_{snake}, int32(pair & 0xFFFFFFFF))
589}}
590
591func Lift{upper_kind}{camel}(handle int32) *witTypes.{upper_kind}Reader[{payload}] {{
592	return witTypes.Make{upper_kind}Reader[{payload}](&wasm_{kind}_vtable_{snake}, handle)
593}}
594"#
595        );
596
597        data
598    }
599
600    fn mangle_name(&self, resolve: &Resolve, ty: Type, local: Option<&WorldKey>) -> String {
601        // TODO: Ensure the returned name is always distinct for distinct types
602        // (e.g. by incorporating interface version numbers and/or additional
603        // mangling as needed).
604        match ty {
605            Type::Bool => "bool".into(),
606            Type::U8 => "u8".into(),
607            Type::U16 => "u16".into(),
608            Type::U32 => "u32".into(),
609            Type::U64 => "u64".into(),
610            Type::S8 => "s8".into(),
611            Type::S16 => "s16".into(),
612            Type::S32 => "s32".into(),
613            Type::S64 => "s64".into(),
614            Type::ErrorContext => "error_context".into(),
615            Type::F32 => "f32".into(),
616            Type::F64 => "f64".into(),
617            Type::Char => "char".into(),
618            Type::String => "string".into(),
619            Type::Id(id) => {
620                let ty = &resolve.types[id];
621                match &ty.kind {
622                    TypeDefKind::Record(_)
623                    | TypeDefKind::Variant(_)
624                    | TypeDefKind::Enum(_)
625                    | TypeDefKind::Flags(_)
626                    | TypeDefKind::Resource => {
627                        let package = match ty.owner {
628                            TypeOwner::Interface(interface) => {
629                                let key = self
630                                    .interface_names
631                                    .get(&interface)
632                                    .cloned()
633                                    .unwrap_or(WorldKey::Interface(interface));
634
635                                if local == Some(&key) {
636                                    String::new()
637                                } else {
638                                    format!(
639                                        "{}_",
640                                        self.interface_name(
641                                            resolve,
642                                            Some(
643                                                &self
644                                                    .interface_names
645                                                    .get(&interface)
646                                                    .cloned()
647                                                    .unwrap_or(WorldKey::Interface(interface))
648                                            )
649                                        )
650                                    )
651                                }
652                            }
653                            _ => String::new(),
654                        };
655
656                        let name = ty.name.as_ref().unwrap().to_snake_case();
657
658                        format!("{package}{name}")
659                    }
660                    TypeDefKind::Option(some) => {
661                        format!("option_{}", self.mangle_name(resolve, *some, local))
662                    }
663                    TypeDefKind::Result(result) => format!(
664                        "result_{}_{}",
665                        result
666                            .ok
667                            .map(|ty| self.mangle_name(resolve, ty, local))
668                            .unwrap_or_else(|| "unit".into()),
669                        result
670                            .err
671                            .map(|ty| self.mangle_name(resolve, ty, local))
672                            .unwrap_or_else(|| "unit".into())
673                    ),
674                    TypeDefKind::List(ty) => {
675                        format!("list_{}", self.mangle_name(resolve, *ty, local))
676                    }
677                    TypeDefKind::Tuple(tuple) => {
678                        let types = tuple
679                            .types
680                            .iter()
681                            .map(|ty| self.mangle_name(resolve, *ty, local))
682                            .collect::<Vec<_>>()
683                            .join("_");
684                        format!("tuple{}_{types}", tuple.types.len())
685                    }
686                    TypeDefKind::Handle(Handle::Own(ty) | Handle::Borrow(ty)) => {
687                        self.mangle_name(resolve, Type::Id(*ty), local)
688                    }
689                    TypeDefKind::Type(ty) => self.mangle_name(resolve, *ty, local),
690                    TypeDefKind::Stream(ty) => {
691                        format!(
692                            "stream_{}",
693                            ty.map(|ty| self.mangle_name(resolve, ty, local))
694                                .unwrap_or_else(|| "unit".into())
695                        )
696                    }
697                    TypeDefKind::Future(ty) => {
698                        format!(
699                            "future_{}",
700                            ty.map(|ty| self.mangle_name(resolve, ty, local))
701                                .unwrap_or_else(|| "unit".into())
702                        )
703                    }
704                    TypeDefKind::Map(key, value) => {
705                        format!(
706                            "map_{}_{}",
707                            self.mangle_name(resolve, *key, local),
708                            self.mangle_name(resolve, *value, local)
709                        )
710                    }
711                    kind => todo!("{kind:?}"),
712                }
713            }
714        }
715    }
716}
717
718impl WorldGenerator for Go {
719    // FIXME(#1527): this caused failures in CI at
720    // https://github.com/bytecodealliance/wit-bindgen/actions/runs/21880247244/job/63160400774?pr=1526
721    // and should be fixed at some point by deleting this method and getting
722    // tests passing again.
723    fn uses_nominal_type_ids(&self) -> bool {
724        false
725    }
726
727    fn preprocess(&mut self, resolve: &Resolve, world: WorldId) {
728        _ = world;
729        self.sizes.fill(resolve);
730        self.imports.insert(remote_pkg("runtime"));
731    }
732
733    fn import_interface(
734        &mut self,
735        resolve: &Resolve,
736        name: &WorldKey,
737        id: InterfaceId,
738        _files: &mut Files,
739    ) -> Result<()> {
740        if let WorldKey::Name(_) = name {
741            self.interface_names.insert(id, name.clone());
742        }
743
744        let mut data = {
745            let mut generator = InterfaceGenerator::new(self, resolve, Some((id, name)), true);
746            for (name, ty) in resolve.interfaces[id].types.iter() {
747                if !generator.generator.types.contains(ty) {
748                    generator.generator.types.insert(*ty);
749                    generator.define_type(name, *ty);
750                }
751            }
752            InterfaceData::from(generator)
753        };
754
755        for (_, func) in &resolve.interfaces[id].functions {
756            data.extend(self.import(resolve, func, Some(name)));
757        }
758        self.interfaces
759            .entry(self.interface_name(resolve, Some(name)))
760            .or_default()
761            .extend(data);
762
763        Ok(())
764    }
765
766    fn import_funcs(
767        &mut self,
768        resolve: &Resolve,
769        _world: WorldId,
770        funcs: &[(&str, &Function)],
771        _files: &mut Files,
772    ) {
773        let mut data = InterfaceData::default();
774        for (_, func) in funcs {
775            data.extend(self.import(resolve, func, None));
776        }
777        self.interfaces
778            .entry(self.interface_name(resolve, None))
779            .or_default()
780            .extend(data);
781    }
782
783    fn export_interface(
784        &mut self,
785        resolve: &Resolve,
786        name: &WorldKey,
787        id: InterfaceId,
788        _files: &mut Files,
789    ) -> Result<()> {
790        if let WorldKey::Name(_) = name {
791            self.interface_names.insert(id, name.clone());
792        }
793
794        for (type_name, ty) in &resolve.interfaces[id].types {
795            let exported = matches!(resolve.types[*ty].kind, TypeDefKind::Resource)
796                || self.has_exported_resource(resolve, Type::Id(*ty));
797
798            let mut generator = InterfaceGenerator::new(self, resolve, Some((id, name)), false);
799
800            if exported || !generator.generator.types.contains(ty) {
801                generator.generator.types.insert(*ty);
802                generator.define_type(type_name, *ty);
803            }
804
805            let data = generator.into();
806
807            let name = self.interface_name(resolve, Some(name));
808            if exported {
809                &mut self.export_interfaces
810            } else {
811                &mut self.interfaces
812            }
813            .entry(name)
814            .or_default()
815            .extend(data);
816        }
817
818        for (_, func) in &resolve.interfaces[id].functions {
819            let code = self.export(resolve, func, Some(name));
820            self.src.push_str(&code);
821        }
822
823        Ok(())
824    }
825
826    fn export_funcs(
827        &mut self,
828        resolve: &Resolve,
829        _world: WorldId,
830        funcs: &[(&str, &Function)],
831        _files: &mut Files,
832    ) -> Result<()> {
833        for (_, func) in funcs {
834            let code = self.export(resolve, func, None);
835            self.src.push_str(&code);
836        }
837        Ok(())
838    }
839
840    fn import_types(
841        &mut self,
842        resolve: &Resolve,
843        _world: WorldId,
844        types: &[(&str, TypeId)],
845        _files: &mut Files,
846    ) {
847        let mut generator = InterfaceGenerator::new(self, resolve, None, true);
848        for (name, ty) in types {
849            if !generator.generator.types.contains(ty) {
850                generator.generator.types.insert(*ty);
851                generator.define_type(name, *ty);
852            }
853        }
854        let data = generator.into();
855        self.interfaces
856            .entry(self.interface_name(resolve, None))
857            .or_default()
858            .extend(data);
859    }
860
861    fn finish(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) -> Result<()> {
862        _ = (resolve, id);
863
864        let version = env!("CARGO_PKG_VERSION");
865        let packages = resolve
866            .packages
867            .iter()
868            .map(
869                |(
870                    _,
871                    Package {
872                        name:
873                            PackageName {
874                                namespace,
875                                name,
876                                version,
877                            },
878                        ..
879                    },
880                )| {
881                    let version = if let Some(version) = version {
882                        format!("@{version}")
883                    } else {
884                        String::new()
885                    };
886                    format!("//     {namespace}:{name}{version}")
887                },
888            )
889            .collect::<Vec<_>>()
890            .join("\n");
891        let header = &format!(
892            "// Generated by `wit-bindgen` {version}. DO NOT EDIT!
893//
894// This code was generated from the following packages:
895{packages}
896"
897        );
898
899        let src = mem::take(&mut self.src);
900        let align = self.return_area_align.format(POINTER_SIZE_EXPRESSION);
901        let size = self.return_area_size.format(POINTER_SIZE_EXPRESSION);
902        let imports = self
903            .imports
904            .iter()
905            .map(|s| s.as_str())
906            .chain(self.need_math.then_some(r#""math""#))
907            .chain(self.need_unsafe.then_some(r#""unsafe""#))
908            .collect::<Vec<_>>()
909            .join("\n");
910
911        let (exports_file_path, package_name, main_func) = if self.opts.pkg_name.is_some() {
912            if self.opts.print_remote_pkg_version {
913                println!("{}", remote_pkg_version());
914            }
915            // If a module name is specified, the generated files will be used as a library.
916            ("wit_exports/wit_exports.go", "wit_exports", "")
917        } else {
918            files.push(
919                "go.mod",
920                format!(
921                    r#"module wit_component
922
923go 1.25
924
925require (
926    go.bytecodealliance.org/pkg {REMOTE_PKG_VERSION}
927)
928"#,
929                )
930                .as_bytes(),
931            );
932
933            // If a module name is NOT specified, the generated files will be used as a
934            // standalone executable.
935            (
936                "wit_exports.go",
937                "main",
938                r#"// Unused, but present to make the compiler happy
939func main() {}
940"#,
941            )
942        };
943
944        files.push(
945            exports_file_path,
946            &maybe_gofmt(
947                self.opts.format,
948                format!(
949                    r#"{header}
950package {package_name}
951
952import (
953        "runtime"
954        {imports}
955)
956
957var staticPinner = runtime.Pinner{{}}
958var {EXPORT_RETURN_AREA} = uintptr(witRuntime.Allocate(&staticPinner, {size}, {align}))
959var {SYNC_EXPORT_PINNER} = runtime.Pinner{{}}
960
961{src}
962
963{main_func}
964"#
965                )
966                .as_bytes(),
967            ),
968        );
969
970        for (prefix, interfaces) in [("export_", &self.export_interfaces), ("", &self.interfaces)] {
971            for (name, data) in interfaces {
972                let imports = data.imports();
973                let code = &data.code;
974
975                files.push(
976                    &format!("{prefix}{name}/wit_bindings.go"),
977                    &maybe_gofmt(
978                        self.opts.format,
979                        format!(
980                            "{header}
981package {prefix}{name}
982
983import (
984        {imports}
985)
986
987{code}"
988                        )
989                        .as_bytes(),
990                    ),
991                );
992
993                files.push(
994                    &format!("{prefix}{name}/empty.s"),
995                    r#"// This file exists for testing this package without WebAssembly,
996// allowing empty function bodies with a //go:wasmimport directive.
997// See https://pkg.go.dev/cmd/compile for more information."#
998                        .as_bytes(),
999                );
1000            }
1001        }
1002
1003        Ok(())
1004    }
1005}
1006
1007impl Go {
1008    fn import(
1009        &mut self,
1010        resolve: &Resolve,
1011        func: &Function,
1012        interface: Option<&WorldKey>,
1013    ) -> InterfaceData {
1014        self.visit_futures_and_streams(true, resolve, func, interface);
1015
1016        let async_ = self.opts.async_.is_async(resolve, interface, func, true);
1017
1018        let (variant, prefix) = if async_ {
1019            (AbiVariant::GuestImportAsync, "[async-lower]")
1020        } else {
1021            (AbiVariant::GuestImport, "")
1022        };
1023
1024        let sig = resolve.wasm_signature(variant, func);
1025        let import_name = &func.name;
1026        let name = func.name.to_snake_case().replace('.', "_");
1027        let (camel, has_self) = func_declaration(resolve, func);
1028
1029        let module = match interface {
1030            Some(name) => resolve.name_world_key(name),
1031            None => "$root".to_string(),
1032        };
1033
1034        let params = sig
1035            .params
1036            .iter()
1037            .enumerate()
1038            .map(|(i, param)| format!("arg{i} {}", wasm_type(*param)))
1039            .collect::<Vec<_>>()
1040            .join(", ");
1041
1042        let results = match &sig.results[..] {
1043            [] => "",
1044            [result] => wasm_type(*result),
1045            _ => unreachable!(),
1046        };
1047
1048        let mut imports = BTreeSet::new();
1049        let go_params =
1050            self.func_params(resolve, func, interface, true, &mut imports, has_self, "");
1051        let go_results = self.func_results(resolve, func, interface, true, &mut imports);
1052
1053        let raw_name = format!("wasm_import_{name}");
1054
1055        let go_param_names = has_self
1056            .then(|| "self".to_string())
1057            .into_iter()
1058            .chain(
1059                func.params
1060                    .iter()
1061                    .skip(if has_self { 1 } else { 0 })
1062                    .map(|Param { name, .. }| name.to_lower_camel_case()),
1063            )
1064            .collect::<Vec<_>>();
1065
1066        let mut generator = FunctionGenerator::new(
1067            self,
1068            None,
1069            interface,
1070            interface,
1071            &raw_name,
1072            go_param_names.clone(),
1073            false,
1074            true,
1075        );
1076        generator.imports = imports;
1077
1078        let code = if async_ {
1079            generator.imports.insert(remote_pkg("async"));
1080
1081            let (lower, wasm_params) = if sig.indirect_params {
1082                generator.imports.insert(remote_pkg("runtime"));
1083
1084                let params_pointer = generator.locals.tmp("params");
1085                let abi = generator
1086                    .generator
1087                    .sizes
1088                    .record(func.params.iter().map(|Param { ty, .. }| ty));
1089                let size = abi.size.format(POINTER_SIZE_EXPRESSION);
1090                let align = abi.align.format(POINTER_SIZE_EXPRESSION);
1091                let offsets = generator
1092                    .generator
1093                    .sizes
1094                    .field_offsets(func.params.iter().map(|Param { ty, .. }| ty));
1095
1096                for (name, (offset, ty)) in go_param_names.iter().zip(offsets) {
1097                    let offset = offset.format(POINTER_SIZE_EXPRESSION);
1098                    abi::lower_to_memory(
1099                        resolve,
1100                        &mut generator,
1101                        format!("unsafe.Add(unsafe.Pointer({params_pointer}), {offset})"),
1102                        name.clone(),
1103                        ty,
1104                    );
1105                }
1106
1107                let code = mem::take(&mut generator.src);
1108                generator.need_pinner = true;
1109                (
1110                    format!(
1111                        "{params_pointer} := witRuntime.Allocate({PINNER}, {size}, {align})\n{code}"
1112                    ),
1113                    vec![format!("uintptr({params_pointer})")],
1114                )
1115            } else {
1116                let wasm_params = go_param_names
1117                    .iter()
1118                    .zip(&func.params)
1119                    .flat_map(|(name, Param { ty, .. })| {
1120                        abi::lower_flat(resolve, &mut generator, name.clone(), ty)
1121                    })
1122                    .collect();
1123                (mem::take(&mut generator.src), wasm_params)
1124            };
1125
1126            let wasm_params = wasm_params
1127                .iter()
1128                .map(|v| v.as_str())
1129                .chain(func.result.map(|_| IMPORT_RETURN_AREA))
1130                .collect::<Vec<_>>()
1131                .join(", ");
1132
1133            let lift = if let Some(ty) = func.result {
1134                let result = abi::lift_from_memory(
1135                    resolve,
1136                    &mut generator,
1137                    IMPORT_RETURN_AREA.to_string(),
1138                    &ty,
1139                );
1140                let code = mem::take(&mut generator.src);
1141                if let Type::Id(ty) = ty
1142                    && let TypeDefKind::Tuple(tuple) = &resolve.types[ty].kind
1143                {
1144                    let count = tuple.types.len();
1145                    let tuple = generator.locals.tmp("tuple");
1146
1147                    let results = (0..count)
1148                        .map(|index| format!("{tuple}.F{index}"))
1149                        .collect::<Vec<_>>()
1150                        .join(", ");
1151
1152                    format!(
1153                        "{code}
1154{tuple} := {result}
1155return {results}"
1156                    )
1157                } else {
1158                    format!("{code}\nreturn {result}")
1159                }
1160            } else {
1161                String::new()
1162            };
1163
1164            format!(
1165                "{lower}
1166witAsync.SubtaskWait(uint32({raw_name}({wasm_params})))
1167{lift}
1168"
1169            )
1170        } else {
1171            abi::call(
1172                resolve,
1173                variant,
1174                LiftLower::LowerArgsLiftResults,
1175                func,
1176                &mut generator,
1177                false,
1178            );
1179            mem::take(&mut generator.src)
1180        };
1181
1182        let return_area = |generator: &mut FunctionGenerator<'_>,
1183                           size: ArchitectureSize,
1184                           align: Alignment| {
1185            generator.imports.insert(remote_pkg("runtime"));
1186            generator.need_pinner = true;
1187            let size = size.format(POINTER_SIZE_EXPRESSION);
1188            let align = align.format(POINTER_SIZE_EXPRESSION);
1189            format!(
1190                "{IMPORT_RETURN_AREA} := uintptr(witRuntime.Allocate({PINNER}, {size}, {align}))"
1191            )
1192        };
1193
1194        let return_area = if async_ && func.result.is_some() {
1195            let abi = generator.generator.sizes.record(func.result.as_ref());
1196            return_area(&mut generator, abi.size, abi.align)
1197        } else if !(async_ || generator.return_area_size.is_empty()) {
1198            let size = generator.return_area_size;
1199            let align = generator.return_area_align;
1200            return_area(&mut generator, size, align)
1201        } else {
1202            String::new()
1203        };
1204
1205        let pinner = if generator.need_pinner {
1206            format!(
1207                "{PINNER} := &runtime.Pinner{{}}
1208defer {PINNER}.Unpin()
1209"
1210            )
1211        } else {
1212            String::new()
1213        };
1214
1215        InterfaceData::from_generator_and_code(
1216            generator,
1217            format!(
1218                "
1219//go:wasmimport {module} {prefix}{import_name}
1220func {raw_name}({params}) {results}
1221
1222func {camel}({go_params}) {go_results} {{
1223        {pinner}
1224        {return_area}
1225        {code}
1226}}
1227"
1228            ),
1229        )
1230    }
1231
1232    fn export(
1233        &mut self,
1234        resolve: &Resolve,
1235        func: &Function,
1236        interface: Option<&WorldKey>,
1237    ) -> String {
1238        self.visit_futures_and_streams(false, resolve, func, interface);
1239
1240        let async_ = self.opts.async_.is_async(resolve, interface, func, false);
1241
1242        let (variant, prefix) = if async_ {
1243            (AbiVariant::GuestExportAsync, "[async-lift]")
1244        } else {
1245            (AbiVariant::GuestExport, "")
1246        };
1247
1248        let sig = resolve.wasm_signature(variant, func);
1249        let core_module_name = interface.map(|v| resolve.name_world_key(v));
1250        let export_name = func.legacy_core_export_name(core_module_name.as_deref());
1251        let name = self.func_name(resolve, interface, func);
1252
1253        let params = sig
1254            .params
1255            .iter()
1256            .enumerate()
1257            .map(|(i, param)| format!("arg{i} {}", wasm_type(*param)))
1258            .collect::<Vec<_>>()
1259            .join(", ");
1260
1261        let results = match &sig.results[..] {
1262            [] => "",
1263            [result] => wasm_type(*result),
1264            _ => unreachable!(),
1265        };
1266
1267        let unpin_params =
1268            sig.indirect_params || abi::guest_export_params_have_allocations(resolve, func);
1269
1270        let param_names = (0..sig.params.len()).map(|i| format!("arg{i}")).collect();
1271        let mut generator = FunctionGenerator::new(
1272            self,
1273            Some(&name),
1274            interface,
1275            None,
1276            "INVALID",
1277            param_names,
1278            unpin_params,
1279            false,
1280        );
1281        abi::call(
1282            resolve,
1283            variant,
1284            LiftLower::LiftArgsLowerResults,
1285            func,
1286            &mut generator,
1287            async_,
1288        );
1289        let code = generator.src;
1290        let imports = generator.imports;
1291        let need_unsafe = generator.need_unsafe;
1292        self.need_math |= generator.need_math;
1293        self.need_unsafe |= need_unsafe;
1294        self.imports.extend(imports);
1295
1296        let (pinner, other, start, end) = if async_ {
1297            self.imports.insert(remote_pkg("async"));
1298
1299            let module = match interface {
1300                Some(name) => resolve.name_world_key(name),
1301                None => "$root".to_string(),
1302            };
1303
1304            let function = &func.name;
1305
1306            let task_return_params = func
1307                .result
1308                .map(|ty| {
1309                    let mut storage = vec![WasmType::I32; MAX_FLAT_PARAMS];
1310                    let mut flat = FlatTypes::new(&mut storage);
1311                    if resolve.push_flat(&ty, &mut flat) {
1312                        flat.to_vec()
1313                    } else {
1314                        vec![WasmType::I32]
1315                    }
1316                })
1317                .unwrap_or_default()
1318                .into_iter()
1319                .enumerate()
1320                .map(|(i, ty)| {
1321                    let ty = wasm_type(ty);
1322                    format!("arg{i} {ty}")
1323                })
1324                .collect::<Vec<_>>()
1325                .join(", ");
1326
1327            (
1328                if abi::guest_export_needs_post_return(resolve, func) {
1329                    format!("{PINNER} := &runtime.Pinner{{}}")
1330                } else {
1331                    String::new()
1332                },
1333                format!(
1334                    "
1335
1336//go:wasmexport [callback]{prefix}{export_name}
1337func wasm_export_callback_{name}(event0 uint32, event1 uint32, event2 uint32) uint32 {{
1338        return witAsync.Callback(event0, event1, event2)
1339}}
1340
1341//go:wasmimport [export]{module} [task-return]{function}
1342func wasm_export_task_return_{name}({task_return_params})
1343"
1344                ),
1345                "return int32(witAsync.Run(func() {",
1346                "}))",
1347            )
1348        } else if abi::guest_export_needs_post_return(resolve, func) {
1349            (
1350                format!("{PINNER} := &{SYNC_EXPORT_PINNER}"),
1351                format!(
1352                    "
1353
1354//go:wasmexport cabi_post_{export_name}
1355func wasm_export_post_return_{name}(result {results}) {{
1356        syncExportPinner.Unpin()
1357}}
1358"
1359                ),
1360                "",
1361                "",
1362            )
1363        } else {
1364            (String::new(), String::new(), "", "")
1365        };
1366
1367        if self.opts.generate_stubs {
1368            let (camel, has_self) = func_declaration(resolve, func);
1369
1370            let mut imports = BTreeSet::new();
1371            let params =
1372                self.func_params(resolve, func, interface, false, &mut imports, has_self, "_");
1373            let results = self.func_results(resolve, func, interface, false, &mut imports);
1374
1375            self.export_interfaces
1376                .entry(self.interface_name(resolve, interface))
1377                .or_default()
1378                .extend(InterfaceData {
1379                    code: format!(
1380                        r#"
1381func {camel}({params}) {results} {{
1382        panic("not implemented")
1383}}
1384"#
1385                    ),
1386                    imports,
1387                    ..InterfaceData::default()
1388                });
1389        }
1390
1391        format!(
1392            "
1393//go:wasmexport {prefix}{export_name}
1394func wasm_export_{name}({params}) {results} {{
1395        {start}
1396        {pinner}
1397        {code}
1398        {end}
1399}}{other}
1400"
1401        )
1402    }
1403
1404    #[expect(clippy::too_many_arguments, reason = "required context for codegen")]
1405    fn func_params(
1406        &mut self,
1407        resolve: &Resolve,
1408        func: &Function,
1409        interface: Option<&WorldKey>,
1410        in_import: bool,
1411        imports: &mut BTreeSet<String>,
1412        has_self: bool,
1413        prefix: &str,
1414    ) -> String {
1415        func.params
1416            .iter()
1417            .skip(if has_self { 1 } else { 0 })
1418            .map(|Param { name, ty, .. }| {
1419                let name = name.to_lower_camel_case();
1420                let ty = self.type_name(resolve, *ty, interface, in_import, imports);
1421                format!("{prefix}{name} {ty}")
1422            })
1423            .collect::<Vec<_>>()
1424            .join(", ")
1425    }
1426
1427    fn func_results(
1428        &mut self,
1429        resolve: &Resolve,
1430        func: &Function,
1431        interface: Option<&WorldKey>,
1432        in_import: bool,
1433        imports: &mut BTreeSet<String>,
1434    ) -> String {
1435        if let Some(ty) = &func.result {
1436            if let Type::Id(id) = ty
1437                && let TypeDefKind::Tuple(tuple) = &resolve.types[*id].kind
1438            {
1439                let types = tuple
1440                    .types
1441                    .iter()
1442                    .map(|ty| self.type_name(resolve, *ty, interface, in_import, imports))
1443                    .collect::<Vec<_>>()
1444                    .join(", ");
1445                format!("({types})")
1446            } else {
1447                self.type_name(resolve, *ty, interface, in_import, imports)
1448            }
1449        } else {
1450            String::new()
1451        }
1452    }
1453
1454    fn visit_futures_and_streams(
1455        &mut self,
1456        in_import: bool,
1457        resolve: &Resolve,
1458        func: &Function,
1459        interface: Option<&WorldKey>,
1460    ) {
1461        for (index, ty) in func
1462            .find_futures_and_streams(resolve)
1463            .into_iter()
1464            .enumerate()
1465        {
1466            let payload_type = match &resolve.types[ty].kind {
1467                TypeDefKind::Future(ty) => {
1468                    self.need_future = true;
1469                    ty
1470                }
1471                TypeDefKind::Stream(ty) => {
1472                    self.need_stream = true;
1473                    ty
1474                }
1475                _ => unreachable!(),
1476            };
1477
1478            let exported = payload_type
1479                .map(|ty| self.has_exported_resource(resolve, ty))
1480                .unwrap_or(false);
1481
1482            if let hash_map::Entry::Vacant(e) = self.futures_and_streams.entry((ty, exported)) {
1483                e.insert(interface.cloned());
1484
1485                let data = self.future_or_stream(
1486                    resolve,
1487                    ty,
1488                    index,
1489                    in_import,
1490                    in_import || !exported,
1491                    interface,
1492                    &func.name,
1493                );
1494
1495                let name = self.interface_name(resolve, interface);
1496                if in_import || !exported {
1497                    &mut self.interfaces
1498                } else {
1499                    &mut self.export_interfaces
1500                }
1501                .entry(name)
1502                .or_default()
1503                .extend(data);
1504            }
1505        }
1506    }
1507
1508    fn has_exported_resource(&self, resolve: &Resolve, ty: Type) -> bool {
1509        any(resolve, ty, &|ty| {
1510            if let Type::Id(id) = ty
1511                && let TypeDefKind::Resource = &resolve.types[id].kind
1512                && let Direction::Export = self.resources.get(&id).unwrap()
1513            {
1514                true
1515            } else {
1516                false
1517            }
1518        })
1519    }
1520
1521    fn interface_name(&self, resolve: &Resolve, interface: Option<&WorldKey>) -> String {
1522        match interface {
1523            Some(WorldKey::Name(name)) => name.to_snake_case(),
1524            Some(WorldKey::Interface(id)) => {
1525                let interface = &resolve.interfaces[*id];
1526                let package = &resolve.packages[interface.package.unwrap()];
1527                let package_has_multiple_versions = resolve.packages.iter().any(|(_, p)| {
1528                    p.name.namespace == package.name.namespace
1529                        && p.name.name == package.name.name
1530                        && p.name.version != package.name.version
1531                });
1532                let version = if package_has_multiple_versions || self.opts.include_versions {
1533                    if let Some(version) = &package.name.version {
1534                        format!("{}_", version.to_string().replace(['.', '-', '+'], "_"))
1535                    } else {
1536                        String::new()
1537                    }
1538                } else {
1539                    String::new()
1540                };
1541                let namespace = package.name.namespace.to_snake_case();
1542                let package = package.name.name.to_snake_case();
1543                let interface = interface.name.as_ref().unwrap().to_snake_case();
1544                format!("{namespace}_{package}_{version}{interface}")
1545            }
1546            None => "wit_world".into(),
1547        }
1548    }
1549
1550    fn func_name(
1551        &self,
1552        resolve: &Resolve,
1553        interface: Option<&WorldKey>,
1554        func: &Function,
1555    ) -> String {
1556        let prefix = self.interface_name(resolve, interface);
1557        let name = func.name.to_snake_case().replace('.', "_");
1558
1559        format!("{prefix}_{name}")
1560    }
1561}
1562
1563struct FunctionGenerator<'a> {
1564    generator: &'a mut Go,
1565    name: Option<&'a str>,
1566    interface: Option<&'a WorldKey>,
1567    interface_for_types: Option<&'a WorldKey>,
1568    function_to_call: &'a str,
1569    param_names: Vec<String>,
1570    unpin_params: bool,
1571    in_import: bool,
1572    locals: Ns,
1573    src: String,
1574    block_storage: Vec<String>,
1575    blocks: Vec<(String, Vec<String>)>,
1576    need_unsafe: bool,
1577    need_pinner: bool,
1578    need_math: bool,
1579    collect_lifters: bool,
1580    lifter_count: u32,
1581    return_area_size: ArchitectureSize,
1582    return_area_align: Alignment,
1583    imports: BTreeSet<String>,
1584}
1585
1586impl<'a> FunctionGenerator<'a> {
1587    #[expect(clippy::too_many_arguments, reason = "required context for codegen")]
1588    fn new(
1589        generator: &'a mut Go,
1590        name: Option<&'a str>,
1591        interface: Option<&'a WorldKey>,
1592        interface_for_types: Option<&'a WorldKey>,
1593        function_to_call: &'a str,
1594        param_names: Vec<String>,
1595        unpin_params: bool,
1596        in_import: bool,
1597    ) -> Self {
1598        let mut locals = Ns::default();
1599        for name in &param_names {
1600            locals.insert(name).unwrap();
1601        }
1602
1603        Self {
1604            generator,
1605            name,
1606            interface,
1607            interface_for_types,
1608            function_to_call,
1609            param_names,
1610            unpin_params,
1611            in_import,
1612            locals,
1613            src: String::new(),
1614            block_storage: Vec::new(),
1615            blocks: Vec::new(),
1616            need_unsafe: false,
1617            need_pinner: false,
1618            need_math: false,
1619            collect_lifters: false,
1620            lifter_count: 0,
1621            return_area_size: ArchitectureSize::default(),
1622            return_area_align: Alignment::default(),
1623            imports: BTreeSet::new(),
1624        }
1625    }
1626
1627    fn type_name(&mut self, resolve: &Resolve, ty: Type) -> String {
1628        self.generator.type_name(
1629            resolve,
1630            ty,
1631            self.interface_for_types,
1632            self.in_import,
1633            &mut self.imports,
1634        )
1635    }
1636
1637    fn package_for_owner(
1638        &mut self,
1639        resolve: &Resolve,
1640        owner: Option<&WorldKey>,
1641        ty: TypeId,
1642    ) -> String {
1643        self.generator.package_for_owner(
1644            resolve,
1645            owner,
1646            ty,
1647            self.interface_for_types,
1648            self.in_import,
1649            &mut self.imports,
1650        )
1651    }
1652}
1653
1654impl Bindgen for FunctionGenerator<'_> {
1655    type Operand = String;
1656
1657    fn sizes(&self) -> &SizeAlign {
1658        &self.generator.sizes
1659    }
1660
1661    fn push_block(&mut self) {
1662        let prev = mem::take(&mut self.src);
1663        self.block_storage.push(prev);
1664    }
1665
1666    fn finish_block(&mut self, operands: &mut Vec<String>) {
1667        let to_restore = self.block_storage.pop().unwrap();
1668        let src = mem::replace(&mut self.src, to_restore);
1669        self.blocks.push((src, mem::take(operands)));
1670    }
1671
1672    fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String {
1673        if self.in_import {
1674            self.return_area_size = self.return_area_size.max(size);
1675            self.return_area_align = self.return_area_align.max(align);
1676
1677            if !self.return_area_size.is_empty() {
1678                self.need_pinner = true;
1679                self.imports.insert(remote_pkg("runtime"));
1680            }
1681
1682            IMPORT_RETURN_AREA.into()
1683        } else {
1684            self.generator.return_area_size = self.generator.return_area_size.max(size);
1685            self.generator.return_area_align = self.generator.return_area_align.max(align);
1686            EXPORT_RETURN_AREA.into()
1687        }
1688    }
1689
1690    fn is_list_canonical(&self, _: &Resolve, ty: &Type) -> bool {
1691        matches!(
1692            ty,
1693            Type::U8
1694                | Type::S8
1695                | Type::U16
1696                | Type::S16
1697                | Type::U32
1698                | Type::S32
1699                | Type::U64
1700                | Type::S64
1701                | Type::F32
1702                | Type::F64
1703        )
1704    }
1705
1706    fn emit(
1707        &mut self,
1708        resolve: &Resolve,
1709        instruction: &Instruction<'_>,
1710        operands: &mut Vec<String>,
1711        results: &mut Vec<String>,
1712    ) {
1713        let store = |me: &mut Self, src, pointer, offset: &ArchitectureSize, ty| {
1714            me.need_unsafe = true;
1715            let offset = offset.format(POINTER_SIZE_EXPRESSION);
1716            uwriteln!(
1717                me.src,
1718                "*(*{ty})(unsafe.Add(unsafe.Pointer({pointer}), {offset})) = {src}"
1719            );
1720        };
1721        let load = |me: &mut Self,
1722                    results: &mut Vec<String>,
1723                    pointer,
1724                    offset: &ArchitectureSize,
1725                    ty,
1726                    cast: &dyn Fn(String) -> String| {
1727            me.need_unsafe = true;
1728            let offset = offset.format(POINTER_SIZE_EXPRESSION);
1729            results.push(cast(format!(
1730                "*(*{ty})(unsafe.Add(unsafe.Pointer({pointer}), {offset}))"
1731            )));
1732        };
1733
1734        match instruction {
1735            Instruction::GetArg { nth } => results.push(self.param_names[*nth].clone()),
1736            Instruction::StringLower { .. } => {
1737                self.need_pinner = true;
1738                self.need_unsafe = true;
1739                let string = &operands[0];
1740                let utf8 = self.locals.tmp("utf8");
1741                uwriteln!(
1742                    self.src,
1743                    "{utf8} := unsafe.Pointer(unsafe.StringData({string}))\n\
1744                     {PINNER}.Pin({utf8})"
1745                );
1746                results.push(format!("uintptr({utf8})"));
1747                results.push(format!("uint32(len({string}))"));
1748            }
1749            Instruction::StringLift { .. } => {
1750                self.need_unsafe = true;
1751                let pointer = &operands[0];
1752                let length = &operands[1];
1753                let value = self.locals.tmp("value");
1754                uwriteln!(
1755                    self.src,
1756                    "{value} := unsafe.String((*uint8)(unsafe.Pointer({pointer})), {length})"
1757                );
1758                results.push(value)
1759            }
1760            Instruction::ListCanonLower { .. } => {
1761                self.need_pinner = true;
1762                self.need_unsafe = true;
1763                let slice = &operands[0];
1764                let data = self.locals.tmp("data");
1765                uwriteln!(
1766                    self.src,
1767                    "{data} := unsafe.Pointer(unsafe.SliceData({slice}))\n\
1768                     {PINNER}.Pin({data})"
1769                );
1770                results.push(format!("uintptr({data})"));
1771                results.push(format!("uint32(len({slice}))"));
1772            }
1773            Instruction::ListCanonLift { element, .. } => {
1774                self.need_unsafe = true;
1775                let pointer = &operands[0];
1776                let length = &operands[1];
1777                let ty = self.type_name(resolve, **element);
1778                let value = self.locals.tmp("value");
1779                uwriteln!(
1780                    self.src,
1781                    "{value} := unsafe.Slice((*{ty})(unsafe.Pointer({pointer})), {length})"
1782                );
1783                results.push(value)
1784            }
1785            Instruction::ListLower { element, .. } => {
1786                self.need_unsafe = true;
1787                self.need_pinner = true;
1788                self.imports.insert(remote_pkg("runtime"));
1789                let (body, _) = self.blocks.pop().unwrap();
1790                let value = &operands[0];
1791                let slice = self.locals.tmp("slice");
1792                let result = self.locals.tmp("result");
1793                let length = self.locals.tmp("length");
1794                let size = self
1795                    .generator
1796                    .sizes
1797                    .size(element)
1798                    .format(POINTER_SIZE_EXPRESSION);
1799                let align = self
1800                    .generator
1801                    .sizes
1802                    .align(element)
1803                    .format(POINTER_SIZE_EXPRESSION);
1804                uwriteln!(
1805                    self.src,
1806                    "{slice} := {value}
1807{length} := uint32(len({slice}))
1808{result} := witRuntime.Allocate({PINNER}, uintptr({length} * {size}), {align})
1809for index, {ITER_ELEMENT} := range {slice} {{
1810        {ITER_BASE_POINTER} := unsafe.Add({result}, index * {size})
1811        {body}
1812}}
1813"
1814                );
1815                results.push(format!("uintptr({result})"));
1816                results.push(length);
1817            }
1818            Instruction::ListLift { element, .. } => {
1819                self.need_unsafe = true;
1820                let (body, body_results) = self.blocks.pop().unwrap();
1821                let value = &operands[0];
1822                let length = &operands[1];
1823                let result = self.locals.tmp("result");
1824                let size = self
1825                    .generator
1826                    .sizes
1827                    .size(element)
1828                    .format(POINTER_SIZE_EXPRESSION);
1829                let element_type = self.type_name(resolve, **element);
1830                let body_result = &body_results[0];
1831                uwriteln!(
1832                    self.src,
1833                    "{result} := make([]{element_type}, 0, {length})
1834for index := 0; index < int({length}); index++ {{
1835        {ITER_BASE_POINTER} := unsafe.Add(unsafe.Pointer({value}), index * {size})
1836        {body}
1837        {result} = append({result}, {body_result})
1838}}
1839"
1840                );
1841                results.push(result);
1842            }
1843            Instruction::CallInterface { func, .. } => {
1844                if self.unpin_params {
1845                    self.imports.insert(remote_pkg("runtime"));
1846                    uwriteln!(self.src, "witRuntime.Unpin()");
1847                }
1848
1849                let name = func.item_name().to_upper_camel_case();
1850                let package = format!(
1851                    "export_{}",
1852                    self.generator.interface_name(resolve, self.interface)
1853                );
1854
1855                let call = match &func.kind {
1856                    FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
1857                        let args = operands.join(", ");
1858                        let call = format!("{package}.{name}({args})");
1859                        self.imports.insert(self.generator.mod_pkg(true, &package));
1860                        call
1861                    }
1862                    FunctionKind::Constructor(ty) => {
1863                        let args = operands.join(", ");
1864                        let ty = resolve.types[*ty]
1865                            .name
1866                            .as_ref()
1867                            .unwrap()
1868                            .to_upper_camel_case();
1869                        let call = format!("{package}.Make{ty}({args})");
1870                        self.imports.insert(self.generator.mod_pkg(true, &package));
1871                        call
1872                    }
1873                    FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) => {
1874                        let target = &operands[0];
1875                        let args = operands[1..].join(", ");
1876                        format!("({target}).{name}({args})")
1877                    }
1878                    FunctionKind::Static(ty) | FunctionKind::AsyncStatic(ty) => {
1879                        let args = operands.join(", ");
1880                        let ty = self.type_name(resolve, Type::Id(*ty));
1881                        format!("{ty}{name}({args})")
1882                    }
1883                };
1884
1885                if let Some(ty) = func.result {
1886                    let result = self.locals.tmp("result");
1887                    if let Type::Id(ty) = ty
1888                        && let TypeDefKind::Tuple(tuple) = &resolve.types[ty].kind
1889                    {
1890                        let count = tuple.types.len();
1891                        self.generator.tuples.insert(count);
1892                        self.imports.insert(remote_pkg("types"));
1893
1894                        let results = (0..count)
1895                            .map(|_| self.locals.tmp("result"))
1896                            .collect::<Vec<_>>()
1897                            .join(", ");
1898
1899                        let types = tuple
1900                            .types
1901                            .iter()
1902                            .map(|&ty| self.type_name(resolve, ty))
1903                            .collect::<Vec<_>>()
1904                            .join(", ");
1905
1906                        uwriteln!(
1907                            self.src,
1908                            "{results} := {call}
1909{result} := witTypes.Tuple{count}[{types}]{{{results}}}"
1910                        );
1911                    } else {
1912                        uwriteln!(self.src, "{result} := {call}");
1913                    }
1914                    results.push(result);
1915                } else {
1916                    uwriteln!(self.src, "{call}");
1917                }
1918            }
1919            Instruction::Return { func, .. } => {
1920                if let Some(ty) = func.result {
1921                    let result = &operands[0];
1922                    if self.in_import
1923                        && let Type::Id(ty) = ty
1924                        && let TypeDefKind::Tuple(tuple) = &resolve.types[ty].kind
1925                    {
1926                        let count = tuple.types.len();
1927                        let tuple = self.locals.tmp("tuple");
1928
1929                        let results = (0..count)
1930                            .map(|index| format!("{tuple}.F{index}"))
1931                            .collect::<Vec<_>>()
1932                            .join(", ");
1933
1934                        uwriteln!(
1935                            self.src,
1936                            "{tuple} := {result}
1937return {results}"
1938                        );
1939                    } else {
1940                        uwriteln!(self.src, "return {result}");
1941                    }
1942                }
1943            }
1944            Instruction::AsyncTaskReturn { .. } => {
1945                let name = self.name.unwrap();
1946                let args = operands.join(", ");
1947                uwriteln!(self.src, "wasm_export_task_return_{name}({args})");
1948            }
1949            Instruction::LengthStore { offset } => store(
1950                self,
1951                &format!("uint32({})", operands[0]),
1952                &operands[1],
1953                offset,
1954                "uint32",
1955            ),
1956            Instruction::PointerStore { offset } => store(
1957                self,
1958                &format!("uint32(uintptr({}))", operands[0]),
1959                &operands[1],
1960                offset,
1961                "uint32",
1962            ),
1963            Instruction::I32Store8 { offset } => store(
1964                self,
1965                &format!("int8({})", operands[0]),
1966                &operands[1],
1967                offset,
1968                "int8",
1969            ),
1970            Instruction::I32Store16 { offset } => store(
1971                self,
1972                &format!("int16({})", operands[0]),
1973                &operands[1],
1974                offset,
1975                "int16",
1976            ),
1977            Instruction::I32Store { offset } => {
1978                store(self, &operands[0], &operands[1], offset, "int32")
1979            }
1980            Instruction::I64Store { offset } => {
1981                store(self, &operands[0], &operands[1], offset, "int64")
1982            }
1983            Instruction::F32Store { offset } => {
1984                store(self, &operands[0], &operands[1], offset, "float32")
1985            }
1986            Instruction::F64Store { offset } => {
1987                store(self, &operands[0], &operands[1], offset, "float64")
1988            }
1989            Instruction::LengthLoad { offset } => {
1990                load(self, results, &operands[0], offset, "uint32", &|v| v)
1991            }
1992            Instruction::PointerLoad { offset } => {
1993                load(self, results, &operands[0], offset, "uint32", &|v| {
1994                    format!("uintptr({v})")
1995                })
1996            }
1997            Instruction::I32Load8U { offset } => {
1998                load(self, results, &operands[0], offset, "uint32", &|v| {
1999                    format!("uint8({v})")
2000                })
2001            }
2002            Instruction::I32Load8S { offset } => {
2003                load(self, results, &operands[0], offset, "uint32", &|v| {
2004                    format!("int8({v})")
2005                })
2006            }
2007            Instruction::I32Load16U { offset } => {
2008                load(self, results, &operands[0], offset, "uint32", &|v| {
2009                    format!("uint16({v})")
2010                })
2011            }
2012            Instruction::I32Load16S { offset } => {
2013                load(self, results, &operands[0], offset, "uint32", &|v| {
2014                    format!("int16({v})")
2015                })
2016            }
2017            Instruction::I32Load { offset } => {
2018                load(self, results, &operands[0], offset, "int32", &|v| v)
2019            }
2020            Instruction::I64Load { offset } => {
2021                load(self, results, &operands[0], offset, "int64", &|v| v)
2022            }
2023            Instruction::F32Load { offset } => {
2024                load(self, results, &operands[0], offset, "float32", &|v| v)
2025            }
2026            Instruction::F64Load { offset } => {
2027                load(self, results, &operands[0], offset, "float64", &|v| v)
2028            }
2029            Instruction::BoolFromI32 => results.push(format!("({} != 0)", operands[0])),
2030            Instruction::U8FromI32 => results.push(format!("uint8({})", operands[0])),
2031            Instruction::S8FromI32 => results.push(format!("int8({})", operands[0])),
2032            Instruction::U16FromI32 => results.push(format!("uint16({})", operands[0])),
2033            Instruction::S16FromI32 => results.push(format!("int16({})", operands[0])),
2034            Instruction::U32FromI32 => results.push(format!("uint32({})", operands[0])),
2035            Instruction::S32FromI32 | Instruction::S64FromI64 => {
2036                results.push(operands.pop().unwrap())
2037            }
2038            Instruction::U64FromI64 => results.push(format!("uint64({})", operands[0])),
2039            Instruction::I32FromBool => {
2040                let value = &operands[0];
2041                let result = self.locals.tmp("result");
2042                uwriteln!(
2043                    self.src,
2044                    "var {result} int32
2045if {value} {{
2046        {result} = 1
2047}} else {{
2048        {result} = 0
2049}}"
2050                );
2051                results.push(result);
2052            }
2053            Instruction::I32FromU8
2054            | Instruction::I32FromS8
2055            | Instruction::I32FromU16
2056            | Instruction::I32FromS16
2057            | Instruction::I32FromU32 => {
2058                results.push(format!("int32({})", operands[0]));
2059            }
2060            Instruction::I32FromS32 | Instruction::I64FromS64 => {
2061                results.push(operands.pop().unwrap())
2062            }
2063            Instruction::I64FromU64 => results.push(format!("int64({})", operands[0])),
2064            Instruction::CoreF32FromF32
2065            | Instruction::CoreF64FromF64
2066            | Instruction::F32FromCoreF32
2067            | Instruction::F64FromCoreF64 => results.push(operands.pop().unwrap()),
2068            Instruction::CharFromI32 => results.push(format!("rune({})", operands[0])),
2069            Instruction::I32FromChar => results.push(format!("int32({})", operands[0])),
2070            Instruction::TupleLower { tuple, .. } => {
2071                let op = &operands[0];
2072                for index in 0..tuple.types.len() {
2073                    results.push(format!("({op}).F{index}"));
2074                }
2075            }
2076            Instruction::TupleLift { tuple, .. } => {
2077                let count = tuple.types.len();
2078                self.generator.tuples.insert(count);
2079                let types = tuple
2080                    .types
2081                    .iter()
2082                    .map(|&ty| self.type_name(resolve, ty))
2083                    .collect::<Vec<_>>()
2084                    .join(", ");
2085                let fields = operands.join(", ");
2086                self.imports.insert(remote_pkg("types"));
2087                results.push(format!("witTypes.Tuple{count}[{types}]{{{fields}}}"));
2088            }
2089            Instruction::FlagsLower { .. } => {
2090                let value = operands.pop().unwrap();
2091                results.push(format!("int32({value})"))
2092            }
2093            Instruction::FlagsLift { flags, .. } => {
2094                let value = operands.pop().unwrap();
2095                let repr = flags_repr(flags);
2096                results.push(format!("{repr}({value})"))
2097            }
2098            Instruction::RecordLower { record, .. } => {
2099                let op = &operands[0];
2100                for field in &record.fields {
2101                    let field = field.name.to_upper_camel_case();
2102                    results.push(format!("({op}).{field}"));
2103                }
2104            }
2105            Instruction::RecordLift { ty, .. } => {
2106                let name = self.type_name(resolve, Type::Id(*ty));
2107                let fields = operands.join(", ");
2108                results.push(format!("{name}{{{fields}}}"));
2109            }
2110            Instruction::OptionLower {
2111                results: result_types,
2112                ..
2113            } => {
2114                self.generator.need_option = true;
2115                self.imports.insert(remote_pkg("types"));
2116                let (some, some_results) = self.blocks.pop().unwrap();
2117                let (none, none_results) = self.blocks.pop().unwrap();
2118                let value = &operands[0];
2119
2120                let result_names = (0..result_types.len())
2121                    .map(|_| self.locals.tmp("option"))
2122                    .collect::<Vec<_>>();
2123
2124                let declarations = result_types
2125                    .iter()
2126                    .zip(&result_names)
2127                    .map(|(ty, name)| {
2128                        let ty = wasm_type(*ty);
2129                        format!("var {name} {ty}")
2130                    })
2131                    .collect::<Vec<_>>()
2132                    .join("\n");
2133
2134                let some_result_assignments = some_results
2135                    .iter()
2136                    .zip(&result_names)
2137                    .map(|(result, name)| format!("{name} = {result}"))
2138                    .collect::<Vec<_>>()
2139                    .join("\n");
2140
2141                let none_result_assignments = none_results
2142                    .iter()
2143                    .zip(&result_names)
2144                    .map(|(result, name)| format!("{name} = {result}"))
2145                    .collect::<Vec<_>>()
2146                    .join("\n");
2147
2148                results.extend(result_names);
2149
2150                uwriteln!(
2151                    self.src,
2152                    r#"{declarations}
2153switch {value}.Tag() {{
2154case witTypes.OptionNone:
2155        {none}
2156        {none_result_assignments}
2157case witTypes.OptionSome:
2158        {VARIANT_PAYLOAD_NAME} := {value}.Some()
2159        {some}
2160        {some_result_assignments}
2161default:
2162        panic("unreachable")
2163}}"#
2164                );
2165            }
2166            Instruction::OptionLift { ty, payload } => {
2167                self.generator.need_option = true;
2168                self.imports.insert(remote_pkg("types"));
2169                let (some, some_results) = self.blocks.pop().unwrap();
2170                let (none, none_results) = self.blocks.pop().unwrap();
2171                assert!(none_results.is_empty());
2172                assert!(some_results.len() == 1);
2173                let some_result = &some_results[0];
2174                let ty = self.type_name(resolve, Type::Id(*ty));
2175                let some_type = self.type_name(resolve, **payload);
2176                let result = self.locals.tmp("option");
2177                let tag = &operands[0];
2178                uwriteln!(
2179                    self.src,
2180                    r#"var {result} {ty}
2181switch {tag} {{
2182case 0:
2183        {none}
2184        {result} = witTypes.None[{some_type}]()
2185case 1:
2186        {some}
2187        {result} = witTypes.Some[{some_type}]({some_result})
2188default:
2189        panic("unreachable")
2190}}"#
2191                );
2192                results.push(result);
2193            }
2194            Instruction::ResultLower {
2195                result,
2196                results: result_types,
2197                ..
2198            } => {
2199                self.generator.need_result = true;
2200                self.imports.insert(remote_pkg("types"));
2201                let (err, err_results) = self.blocks.pop().unwrap();
2202                let (ok, ok_results) = self.blocks.pop().unwrap();
2203                let value = &operands[0];
2204
2205                let result_names = (0..result_types.len())
2206                    .map(|_| self.locals.tmp("option"))
2207                    .collect::<Vec<_>>();
2208
2209                let declarations = result_types
2210                    .iter()
2211                    .zip(&result_names)
2212                    .map(|(ty, name)| {
2213                        let ty = wasm_type(*ty);
2214                        format!("var {name} {ty}")
2215                    })
2216                    .collect::<Vec<_>>()
2217                    .join("\n");
2218
2219                let ok_result_assignments = ok_results
2220                    .iter()
2221                    .zip(&result_names)
2222                    .map(|(result, name)| format!("{name} = {result}"))
2223                    .collect::<Vec<_>>()
2224                    .join("\n");
2225
2226                let err_result_assignments = err_results
2227                    .iter()
2228                    .zip(&result_names)
2229                    .map(|(result, name)| format!("{name} = {result}"))
2230                    .collect::<Vec<_>>()
2231                    .join("\n");
2232
2233                results.extend(result_names);
2234
2235                let ok_set_payload = if result.ok.is_some() {
2236                    format!("{VARIANT_PAYLOAD_NAME} := {value}.Ok()")
2237                } else {
2238                    self.generator.need_unit = true;
2239                    String::new()
2240                };
2241
2242                let err_set_payload = if result.err.is_some() {
2243                    format!("{VARIANT_PAYLOAD_NAME} := {value}.Err()")
2244                } else {
2245                    self.generator.need_unit = true;
2246                    String::new()
2247                };
2248
2249                uwriteln!(
2250                    self.src,
2251                    r#"{declarations}
2252switch {value}.Tag() {{
2253case witTypes.ResultOk:
2254        {ok_set_payload}
2255        {ok}
2256        {ok_result_assignments}
2257case witTypes.ResultErr:
2258        {err_set_payload}
2259        {err}
2260        {err_result_assignments}
2261default:
2262        panic("unreachable")
2263}}"#
2264                );
2265            }
2266            Instruction::ResultLift { ty, result, .. } => {
2267                self.generator.need_result = true;
2268                self.imports.insert(remote_pkg("types"));
2269                let (err, err_results) = self.blocks.pop().unwrap();
2270                let (ok, ok_results) = self.blocks.pop().unwrap();
2271                assert_eq!(ok_results.is_empty(), result.ok.is_none());
2272                assert_eq!(err_results.is_empty(), result.err.is_none());
2273                let ok_result = if result.ok.is_some() {
2274                    &ok_results[0]
2275                } else {
2276                    self.generator.need_unit = true;
2277                    "witTypes.Unit{}"
2278                };
2279                let err_result = if result.err.is_some() {
2280                    &err_results[0]
2281                } else {
2282                    self.generator.need_unit = true;
2283                    "witTypes.Unit{}"
2284                };
2285                let ty = self.type_name(resolve, Type::Id(*ty));
2286                let ok_type = result
2287                    .ok
2288                    .map(|ty| self.type_name(resolve, ty))
2289                    .unwrap_or_else(|| {
2290                        self.generator.need_unit = true;
2291                        "witTypes.Unit".into()
2292                    });
2293                let err_type = result
2294                    .err
2295                    .map(|ty| self.type_name(resolve, ty))
2296                    .unwrap_or_else(|| {
2297                        self.generator.need_unit = true;
2298                        "witTypes.Unit".into()
2299                    });
2300                let result = self.locals.tmp("result");
2301                let tag = &operands[0];
2302                uwriteln!(
2303                    self.src,
2304                    r#"var {result} {ty}
2305switch {tag} {{
2306case 0:
2307        {ok}
2308        {result} = witTypes.Ok[{ok_type}, {err_type}]({ok_result})
2309case 1:
2310        {err}
2311        {result} = witTypes.Err[{ok_type}, {err_type}]({err_result})
2312default:
2313        panic("unreachable")
2314}}"#
2315                );
2316                results.push(result);
2317            }
2318            Instruction::EnumLower { .. } => results.push(format!("int32({})", operands[0])),
2319            Instruction::EnumLift { enum_, .. } => {
2320                results.push(format!("{}({})", int_repr(enum_.tag()), operands[0]))
2321            }
2322            Instruction::VariantLower {
2323                ty,
2324                variant,
2325                results: result_types,
2326                ..
2327            } => {
2328                let blocks = self
2329                    .blocks
2330                    .drain(self.blocks.len() - variant.cases.len()..)
2331                    .collect::<Vec<_>>();
2332
2333                let ty = self.type_name(resolve, Type::Id(*ty));
2334                let value = &operands[0];
2335
2336                let result_names = (0..result_types.len())
2337                    .map(|_| self.locals.tmp("variant"))
2338                    .collect::<Vec<_>>();
2339
2340                let declarations = result_types
2341                    .iter()
2342                    .zip(&result_names)
2343                    .map(|(ty, name)| {
2344                        let ty = wasm_type(*ty);
2345                        format!("var {name} {ty}")
2346                    })
2347                    .collect::<Vec<_>>()
2348                    .join("\n");
2349
2350                let cases = variant
2351                    .cases
2352                    .iter()
2353                    .zip(blocks)
2354                    .map(|(case, (block, block_results))| {
2355                        let assignments = result_names
2356                            .iter()
2357                            .zip(&block_results)
2358                            .map(|(name, result)| format!("{name} = {result}"))
2359                            .collect::<Vec<_>>()
2360                            .join("\n");
2361
2362                        let name = case.name.to_upper_camel_case();
2363
2364                        let set_payload = if case.ty.is_some() {
2365                            format!("{VARIANT_PAYLOAD_NAME} := {value}.{name}()")
2366                        } else {
2367                            String::new()
2368                        };
2369
2370                        format!(
2371                            "case {ty}{name}:
2372        {set_payload}
2373        {block}
2374        {assignments}
2375"
2376                        )
2377                    })
2378                    .collect::<Vec<_>>()
2379                    .join("\n");
2380
2381                results.extend(result_names);
2382
2383                uwriteln!(
2384                    self.src,
2385                    r#"{declarations}
2386switch {value}.Tag() {{
2387{cases}
2388default:
2389        panic("unreachable")
2390}}"#
2391                );
2392            }
2393            Instruction::VariantLift { ty, variant, .. } => {
2394                let blocks = self
2395                    .blocks
2396                    .drain(self.blocks.len() - variant.cases.len()..)
2397                    .collect::<Vec<_>>();
2398
2399                let ty = self.type_name(resolve, Type::Id(*ty));
2400                let result = self.locals.tmp("variant");
2401                let tag = &operands[0];
2402
2403                let (package, name) = if let Some(index) = ty.find('.') {
2404                    (&ty[..index + 1], &ty[index + 1..])
2405                } else {
2406                    ("", ty.as_str())
2407                };
2408
2409                let cases = variant
2410                    .cases
2411                    .iter()
2412                    .zip(blocks)
2413                    .enumerate()
2414                    .map(|(index, (case, (block, block_results)))| {
2415                        assert_eq!(block_results.is_empty(), case.ty.is_none());
2416                        let payload = if case.ty.is_some() {
2417                            &block_results[0]
2418                        } else {
2419                            ""
2420                        };
2421                        let case = case.name.to_upper_camel_case();
2422                        format!(
2423                            "case {index}:
2424        {block}
2425        {result} = {package}Make{name}{case}({payload})
2426"
2427                        )
2428                    })
2429                    .collect::<Vec<_>>()
2430                    .join("\n");
2431
2432                uwriteln!(
2433                    self.src,
2434                    r#"var {result} {ty}
2435switch {tag} {{
2436{cases}
2437default:
2438        panic("unreachable")
2439}}"#
2440                );
2441                results.push(result);
2442            }
2443            Instruction::VariantPayloadName => results.push(VARIANT_PAYLOAD_NAME.into()),
2444            Instruction::IterElem { .. } => results.push(ITER_ELEMENT.into()),
2445            Instruction::IterBasePointer => results.push(ITER_BASE_POINTER.into()),
2446            Instruction::I32Const { val } => results.push(format!("int32({val})")),
2447            Instruction::ConstZero { tys } => {
2448                results.extend(iter::repeat_with(|| "0".into()).take(tys.len()));
2449            }
2450            Instruction::Bitcasts { casts } => {
2451                results.extend(
2452                    casts
2453                        .iter()
2454                        .zip(operands)
2455                        .map(|(which, op)| cast(op, which, &mut self.need_math)),
2456                );
2457            }
2458            Instruction::FutureLower { .. }
2459            | Instruction::StreamLower { .. }
2460            | Instruction::HandleLower {
2461                handle: Handle::Own(_),
2462                ..
2463            } => {
2464                let op = &operands[0];
2465                if self.collect_lifters {
2466                    self.lifter_count += 1;
2467                    let resource = self.locals.tmp("resource");
2468                    let handle = self.locals.tmp("handle");
2469                    uwriteln!(
2470                        self.src,
2471                        "{resource} := {op}
2472{handle} := {resource}.TakeHandle()
2473lifters = append(lifters, func() {{
2474        {resource}.SetHandle({handle})
2475}})"
2476                    );
2477                    results.push(handle)
2478                } else {
2479                    results.push(format!("({op}).TakeHandle()"))
2480                }
2481            }
2482            Instruction::HandleLower {
2483                handle: Handle::Borrow(_),
2484                ..
2485            } => results.push(format!("({}).Handle()", operands[0])),
2486            Instruction::HandleLift { handle, .. } => {
2487                let (which, resource) = match handle {
2488                    Handle::Borrow(resource) => ("Borrow", resource),
2489                    Handle::Own(resource) => ("Own", resource),
2490                };
2491                let handle = &operands[0];
2492                let ty = self.type_name(resolve, Type::Id(*resource));
2493                results.push(format!("{ty}From{which}Handle(int32(uintptr({handle})))"))
2494            }
2495            Instruction::CallWasm { sig, .. } => {
2496                let assignment = match &sig.results[..] {
2497                    [] => String::new(),
2498                    [_] => {
2499                        let result = self.locals.tmp("result");
2500                        let assignment = format!("{result} := ");
2501                        results.push(result);
2502                        assignment
2503                    }
2504                    _ => unreachable!(),
2505                };
2506                let name = &self.function_to_call;
2507                let params = operands.join(", ");
2508                uwriteln!(self.src, "{assignment}{name}({params})")
2509            }
2510            Instruction::Flush { amt } => {
2511                for op in operands.iter().take(*amt) {
2512                    let result = self.locals.tmp("result");
2513                    uwriteln!(self.src, "{result} := {op};");
2514                    results.push(result);
2515                }
2516            }
2517            Instruction::FutureLift { ty, .. } => {
2518                let exported = self.generator.has_exported_resource(resolve, Type::Id(*ty));
2519                let owner = self
2520                    .generator
2521                    .futures_and_streams
2522                    .get(&(*ty, exported))
2523                    .unwrap()
2524                    .clone();
2525                let package = self.package_for_owner(resolve, owner.as_ref(), *ty);
2526                let TypeDefKind::Future(payload_ty) = &resolve.types[*ty].kind else {
2527                    unreachable!()
2528                };
2529                let camel = if let Some(ty) = payload_ty {
2530                    self.generator
2531                        .mangle_name(resolve, *ty, owner.as_ref())
2532                        .to_upper_camel_case()
2533                } else {
2534                    "Unit".into()
2535                };
2536                let handle = &operands[0];
2537                results.push(format!("{package}LiftFuture{camel}({handle})"));
2538            }
2539            Instruction::StreamLift { ty, .. } => {
2540                let exported = self.generator.has_exported_resource(resolve, Type::Id(*ty));
2541                let owner = self
2542                    .generator
2543                    .futures_and_streams
2544                    .get(&(*ty, exported))
2545                    .unwrap()
2546                    .clone();
2547                let package = self.package_for_owner(resolve, owner.as_ref(), *ty);
2548                let TypeDefKind::Stream(payload_ty) = &resolve.types[*ty].kind else {
2549                    unreachable!()
2550                };
2551                let camel = if let Some(ty) = payload_ty {
2552                    self.generator
2553                        .mangle_name(resolve, *ty, owner.as_ref())
2554                        .to_upper_camel_case()
2555                } else {
2556                    "Unit".into()
2557                };
2558                let handle = &operands[0];
2559                results.push(format!("{package}LiftStream{camel}({handle})"));
2560            }
2561            Instruction::MapLower { key, value, .. } => {
2562                self.need_unsafe = true;
2563                self.need_pinner = true;
2564                self.imports.insert(remote_pkg("runtime"));
2565                let (body, _) = self.blocks.pop().unwrap();
2566                let value_op = &operands[0];
2567                let src_map = self.locals.tmp("srcMap");
2568                let result = self.locals.tmp("result");
2569                let length = self.locals.tmp("length");
2570                let idx = self.locals.tmp("idx");
2571                let entry = self.generator.sizes.record([*key, *value]);
2572                let size = entry.size.format(POINTER_SIZE_EXPRESSION);
2573                let align = entry.align.format(POINTER_SIZE_EXPRESSION);
2574                uwriteln!(
2575                    self.src,
2576                    "{src_map} := {value_op}
2577{length} := uint32(len({src_map}))
2578{result} := witRuntime.Allocate({PINNER}, uintptr({length} * {size}), {align})
2579var {idx} int
2580for map_key, map_value := range {src_map} {{
2581        {ITER_BASE_POINTER} := unsafe.Add({result}, {idx} * {size})
2582        {body}
2583        {idx}++
2584}}
2585"
2586                );
2587                results.push(format!("uintptr({result})"));
2588                results.push(length);
2589            }
2590            Instruction::MapLift { key, value, .. } => {
2591                self.need_unsafe = true;
2592                let (body, body_results) = self.blocks.pop().unwrap();
2593                let pointer = &operands[0];
2594                let length = &operands[1];
2595                let result = self.locals.tmp("result");
2596                let entry = self.generator.sizes.record([*key, *value]);
2597                let size = entry.size.format(POINTER_SIZE_EXPRESSION);
2598                let key_type = self.type_name(resolve, **key);
2599                let value_type = self.type_name(resolve, **value);
2600                let body_key = &body_results[0];
2601                let body_value = &body_results[1];
2602                uwriteln!(
2603                    self.src,
2604                    "{result} := make(map[{key_type}]{value_type}, {length})
2605for index := 0; index < int({length}); index++ {{
2606        {ITER_BASE_POINTER} := unsafe.Add(unsafe.Pointer({pointer}), index * {size})
2607        {body}
2608        {result}[{body_key}] = {body_value}
2609}}
2610"
2611                );
2612                results.push(result);
2613            }
2614            Instruction::IterMapKey { .. } => results.push("map_key".into()),
2615            Instruction::IterMapValue { .. } => results.push("map_value".into()),
2616            Instruction::GuestDeallocateMap { .. } | Instruction::GuestDeallocate { .. } => {
2617                // Nothing to do here; should be handled when calling `pinner.Unpin()`
2618            }
2619            _ => unimplemented!("{instruction:?}"),
2620        }
2621    }
2622}
2623
2624struct InterfaceGenerator<'a> {
2625    generator: &'a mut Go,
2626    resolve: &'a Resolve,
2627    interface: Option<(InterfaceId, &'a WorldKey)>,
2628    in_import: bool,
2629    src: String,
2630    imports: BTreeSet<String>,
2631    need_unsafe: bool,
2632    need_runtime: bool,
2633}
2634
2635impl<'a> InterfaceGenerator<'a> {
2636    fn new(
2637        generator: &'a mut Go,
2638        resolve: &'a Resolve,
2639        interface: Option<(InterfaceId, &'a WorldKey)>,
2640        in_import: bool,
2641    ) -> Self {
2642        Self {
2643            generator,
2644            resolve,
2645            interface,
2646            in_import,
2647            src: String::new(),
2648            imports: BTreeSet::new(),
2649            need_unsafe: false,
2650            need_runtime: false,
2651        }
2652    }
2653
2654    fn type_name(&mut self, resolve: &Resolve, ty: Type) -> String {
2655        self.generator.type_name(
2656            resolve,
2657            ty,
2658            self.interface.map(|(_, key)| key),
2659            self.in_import || !self.generator.has_exported_resource(resolve, ty),
2660            &mut self.imports,
2661        )
2662    }
2663}
2664
2665impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
2666    fn resolve(&self) -> &'a Resolve {
2667        self.resolve
2668    }
2669
2670    fn type_record(&mut self, _: TypeId, name: &str, record: &Record, docs: &Docs) {
2671        let name = name.to_upper_camel_case();
2672
2673        let fields = record
2674            .fields
2675            .iter()
2676            .map(|field| {
2677                let ty = self.type_name(self.resolve, field.ty);
2678                let docs = format_docs(&field.docs);
2679                let field = field.name.to_upper_camel_case();
2680                format!("{docs}{field} {ty}")
2681            })
2682            .collect::<Vec<_>>()
2683            .join("\n");
2684
2685        let docs = format_docs(docs);
2686
2687        uwriteln!(
2688            self.src,
2689            "
2690{docs}type {name} struct {{
2691        {fields}
2692}}"
2693        )
2694    }
2695
2696    fn type_resource(&mut self, id: TypeId, name: &str, docs: &Docs) {
2697        self.generator.resources.insert(
2698            id,
2699            if self.in_import {
2700                Direction::Import
2701            } else {
2702                Direction::Export
2703            },
2704        );
2705
2706        let camel = name.to_upper_camel_case();
2707        let module = self
2708            .interface
2709            .map(|(_, key)| self.resolve.name_world_key(key))
2710            .unwrap_or_else(|| "$root".into());
2711
2712        if self.in_import {
2713            self.imports.insert(remote_pkg("runtime"));
2714            self.need_runtime = true;
2715            let docs = format_docs(docs);
2716            uwriteln!(
2717                self.src,
2718                r#"
2719//go:wasmimport {module} [resource-drop]{name}
2720func resourceDrop{camel}(handle int32)
2721
2722{docs}type {camel} struct {{
2723        handle *witRuntime.Handle
2724}}
2725
2726func (self *{camel}) TakeHandle() int32 {{
2727        return self.handle.Take()
2728}}
2729
2730func (self *{camel}) SetHandle(handle int32) {{
2731        self.handle.Set(handle)
2732}}
2733
2734func (self *{camel}) Handle() int32 {{
2735        return self.handle.Use()
2736}}
2737
2738func (self *{camel}) Drop() {{
2739	handle := self.handle.TakeOrNil()
2740	if handle != 0 {{
2741		resourceDrop{camel}(handle)
2742	}}
2743}}
2744
2745func {camel}FromOwnHandle(handleValue int32) *{camel} {{
2746        handle := witRuntime.MakeHandle(handleValue)
2747        value := &{camel}{{handle}}
2748        runtime.AddCleanup(value, func(_ int) {{
2749                handleValue := handle.TakeOrNil()
2750                if handleValue != 0 {{
2751                        resourceDrop{camel}(handleValue)
2752                }}
2753        }}, 0)
2754        return value
2755}}
2756
2757func {camel}FromBorrowHandle(handleValue int32) *{camel} {{
2758	handle := witRuntime.MakeHandle(handleValue)
2759	return &{camel}{{handle}}
2760}}
2761"#
2762            );
2763        } else {
2764            self.need_unsafe = true;
2765            uwriteln!(
2766                self.src,
2767                r#"
2768//go:wasmimport [export]{module} [resource-new]{name}
2769func resourceNew{camel}(pointer unsafe.Pointer) int32
2770
2771//go:wasmimport [export]{module} [resource-rep]{name}
2772func resourceRep{camel}(handle int32) unsafe.Pointer
2773
2774//go:wasmimport [export]{module} [resource-drop]{name}
2775func resourceDrop{camel}(handle int32)
2776
2777//go:wasmexport {module}#[dtor]{name}
2778func resourceDtor{camel}(rep int32) {{
2779        val := (*{camel})(unsafe.Pointer(uintptr(rep)))
2780        val.handle = 0
2781        val.pinner.Unpin()
2782        val.OnDrop()
2783}}
2784
2785func (self *{camel}) TakeHandle() int32 {{
2786	self.pinner.Pin(self)
2787	self.handle = resourceNew{camel}(unsafe.Pointer(self))
2788	return self.handle
2789}}
2790
2791func (self *{camel}) SetHandle(handle int32) {{
2792        if self.handle != handle {{
2793                panic("invalid handle")
2794        }}
2795}}
2796
2797func (self *{camel}) Drop() {{
2798	handle := self.handle
2799	if self.handle != 0 {{
2800		self.handle = 0
2801		resourceDrop{camel}(handle)
2802		self.pinner.Unpin()
2803                self.OnDrop()
2804	}}
2805}}
2806
2807func {camel}FromOwnHandle(handle int32) *{camel} {{
2808	return (*{camel})(unsafe.Pointer(resourceRep{camel}(handle)))
2809}}
2810
2811func {camel}FromBorrowHandle(rep int32) *{camel} {{
2812	return (*{camel})(unsafe.Pointer(uintptr(rep)))
2813}}
2814"#
2815            );
2816
2817            if self.generator.opts.generate_stubs {
2818                self.need_runtime = true;
2819                uwriteln!(
2820                    self.src,
2821                    r#"
2822type {camel} struct {{
2823        pinner runtime.Pinner
2824        handle int32
2825}}
2826
2827func (self *{camel}) OnDrop() {{}}
2828"#
2829                );
2830            }
2831        }
2832    }
2833
2834    fn type_flags(&mut self, _: TypeId, name: &str, flags: &Flags, docs: &Docs) {
2835        let repr = flags_repr(flags);
2836
2837        let name = name.to_upper_camel_case();
2838
2839        let constants = flags
2840            .flags
2841            .iter()
2842            .enumerate()
2843            .map(|(i, flag)| {
2844                let docs = format_docs(&flag.docs);
2845                let flag = flag.name.to_upper_camel_case();
2846                format!("{docs}{name}{flag} {repr} = 1 << {i}")
2847            })
2848            .collect::<Vec<_>>()
2849            .join("\n");
2850
2851        let docs = format_docs(docs);
2852
2853        uwriteln!(
2854            self.src,
2855            "
2856const (
2857{constants}
2858)
2859
2860{docs}type {name} = {repr}"
2861        )
2862    }
2863
2864    fn type_tuple(&mut self, _: TypeId, name: &str, tuple: &Tuple, docs: &Docs) {
2865        self.imports.insert(remote_pkg("types"));
2866        let count = tuple.types.len();
2867        self.generator.tuples.insert(count);
2868        let name = name.to_upper_camel_case();
2869        let docs = format_docs(docs);
2870        let types = tuple
2871            .types
2872            .iter()
2873            .map(|ty| self.type_name(self.resolve, *ty))
2874            .collect::<Vec<_>>()
2875            .join(", ");
2876
2877        uwriteln!(
2878            self.src,
2879            "{docs}type {name} = witTypes.Tuple{count}[{types}]"
2880        );
2881    }
2882
2883    fn type_variant(&mut self, _: TypeId, name: &str, variant: &Variant, docs: &Docs) {
2884        let repr = int_repr(variant.tag());
2885
2886        let name = name.to_upper_camel_case();
2887
2888        let constants = variant
2889            .cases
2890            .iter()
2891            .enumerate()
2892            .map(|(i, case)| {
2893                let docs = format_docs(&case.docs);
2894                let case = case.name.to_upper_camel_case();
2895                format!("{docs}{name}{case} {repr} = {i}")
2896            })
2897            .collect::<Vec<_>>()
2898            .join("\n");
2899
2900        let getters = variant
2901            .cases
2902            .iter()
2903            .filter_map(|case| {
2904                case.ty.map(|ty| {
2905                    let case = case.name.to_upper_camel_case();
2906                    let ty = self.type_name(self.resolve, ty);
2907                    format!(
2908                        r#"func (self {name}) {case}() {ty} {{
2909        if self.tag != {name}{case} {{
2910                panic("tag mismatch")
2911        }}
2912        return self.value.({ty})
2913}}
2914"#
2915                    )
2916                })
2917            })
2918            .collect::<Vec<_>>()
2919            .concat();
2920
2921        let constructors = variant
2922            .cases
2923            .iter()
2924            .map(|case| {
2925                let (param, value) = if let Some(ty) = case.ty {
2926                    let ty = self.type_name(self.resolve, ty);
2927                    (format!("value {ty}"), "value")
2928                } else {
2929                    (String::new(), "nil")
2930                };
2931                let case = case.name.to_upper_camel_case();
2932                format!(
2933                    r#"func Make{name}{case}({param}) {name} {{
2934        return {name}{{{name}{case}, {value}}}
2935}}
2936"#
2937                )
2938            })
2939            .collect::<Vec<_>>()
2940            .concat();
2941
2942        let docs = format_docs(docs);
2943
2944        uwriteln!(
2945            self.src,
2946            "
2947const (
2948{constants}
2949)
2950
2951{docs}type {name} struct {{
2952        tag {repr}
2953        value any
2954}}
2955
2956func (self {name}) Tag() {repr} {{
2957        return self.tag
2958}}
2959
2960{getters}
2961{constructors}
2962"
2963        )
2964    }
2965
2966    fn type_option(&mut self, _: TypeId, name: &str, payload: &Type, docs: &Docs) {
2967        self.generator.need_option = true;
2968        self.imports.insert(remote_pkg("types"));
2969        let name = name.to_upper_camel_case();
2970        let ty = self.type_name(self.resolve, *payload);
2971        let docs = format_docs(docs);
2972        uwriteln!(self.src, "{docs}type {name} = witTypes.Option[{ty}]");
2973    }
2974
2975    fn type_result(&mut self, _: TypeId, name: &str, result: &Result_, docs: &Docs) {
2976        self.generator.need_result = true;
2977        self.imports.insert(remote_pkg("types"));
2978        let name = name.to_upper_camel_case();
2979        let ok_type = result
2980            .ok
2981            .map(|ty| self.type_name(self.resolve, ty))
2982            .unwrap_or_else(|| {
2983                self.generator.need_unit = true;
2984                "witTypes.Unit".into()
2985            });
2986        let err_type = result
2987            .err
2988            .map(|ty| self.type_name(self.resolve, ty))
2989            .unwrap_or_else(|| {
2990                self.generator.need_unit = true;
2991                "witTypes.Unit".into()
2992            });
2993        let docs = format_docs(docs);
2994        uwriteln!(
2995            self.src,
2996            "{docs}type {name} = witTypes.Result[{ok_type}, {err_type}]"
2997        );
2998    }
2999
3000    fn type_enum(&mut self, _: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
3001        let repr = int_repr(enum_.tag());
3002
3003        let name = name.to_upper_camel_case();
3004
3005        let constants = enum_
3006            .cases
3007            .iter()
3008            .enumerate()
3009            .map(|(i, case)| {
3010                let docs = format_docs(&case.docs);
3011                let case = case.name.to_upper_camel_case();
3012                format!("{docs}{name}{case} {repr} = {i}")
3013            })
3014            .collect::<Vec<_>>()
3015            .join("\n");
3016
3017        let docs = format_docs(docs);
3018
3019        uwriteln!(
3020            self.src,
3021            "
3022const (
3023        {constants}
3024)
3025{docs}type {name} = {repr}"
3026        )
3027    }
3028
3029    fn type_alias(&mut self, _: TypeId, name: &str, ty: &Type, docs: &Docs) {
3030        let name = name.to_upper_camel_case();
3031        let ty = self.type_name(self.resolve, *ty);
3032        let docs = format_docs(docs);
3033        uwriteln!(self.src, "{docs}type {name} = {ty}");
3034    }
3035
3036    fn type_list(&mut self, _: TypeId, name: &str, ty: &Type, docs: &Docs) {
3037        let name = name.to_upper_camel_case();
3038        let ty = self.type_name(self.resolve, *ty);
3039        let docs = format_docs(docs);
3040        uwriteln!(self.src, "{docs}type {name} = []{ty}");
3041    }
3042
3043    fn type_fixed_length_list(&mut self, _: TypeId, name: &str, ty: &Type, size: u32, docs: &Docs) {
3044        let name = name.to_upper_camel_case();
3045        let ty = self.type_name(self.resolve, *ty);
3046        let docs = format_docs(docs);
3047        uwriteln!(self.src, "{docs}type {name} = [{size}]{ty}");
3048    }
3049
3050    fn type_map(&mut self, _id: TypeId, name: &str, key: &Type, value: &Type, docs: &Docs) {
3051        let name = name.to_upper_camel_case();
3052        let key = self.type_name(self.resolve, *key);
3053        let value = self.type_name(self.resolve, *value);
3054        let docs = format_docs(docs);
3055        uwriteln!(self.src, "{docs}type {name} = map[{key}]{value}");
3056    }
3057
3058    fn type_builtin(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs) {
3059        _ = (id, name, ty, docs);
3060        todo!()
3061    }
3062
3063    fn type_future(&mut self, id: TypeId, name: &str, _: &Option<Type>, docs: &Docs) {
3064        let name = name.to_upper_camel_case();
3065        let ty = self.type_name(self.resolve, Type::Id(id));
3066        let docs = format_docs(docs);
3067        uwriteln!(self.src, "{docs}type {name} = {ty}");
3068    }
3069
3070    fn type_stream(&mut self, id: TypeId, name: &str, _: &Option<Type>, docs: &Docs) {
3071        let name = name.to_upper_camel_case();
3072        let ty = self.type_name(self.resolve, Type::Id(id));
3073        let docs = format_docs(docs);
3074        uwriteln!(self.src, "{docs}type {name} = {ty}");
3075    }
3076}
3077
3078fn wasm_type(ty: WasmType) -> &'static str {
3079    match ty {
3080        WasmType::I32 => "int32",
3081        WasmType::I64 => "int64",
3082        WasmType::F32 => "float32",
3083        WasmType::F64 => "float64",
3084        WasmType::Pointer => "uintptr",
3085        WasmType::PointerOrI64 => "int64",
3086        WasmType::Length => "uint32",
3087    }
3088}
3089
3090fn format_docs(docs: &Docs) -> String {
3091    docs.contents
3092        .as_ref()
3093        .map(|v| {
3094            v.trim()
3095                .lines()
3096                .map(|line| format!("// {line}\n"))
3097                .collect::<Vec<_>>()
3098                .concat()
3099        })
3100        .unwrap_or_default()
3101}
3102
3103fn flags_repr(flags: &Flags) -> &'static str {
3104    match flags.repr() {
3105        FlagsRepr::U8 => "uint8",
3106        FlagsRepr::U16 => "uint16",
3107        FlagsRepr::U32(1) => "uint32",
3108        _ => unreachable!(),
3109    }
3110}
3111
3112fn int_repr(int: Int) -> &'static str {
3113    match int {
3114        Int::U8 => "uint8",
3115        Int::U16 => "uint16",
3116        Int::U32 => "uint32",
3117        Int::U64 => unreachable!(),
3118    }
3119}
3120
3121fn cast(op: &str, which: &Bitcast, need_math: &mut bool) -> String {
3122    match which {
3123        Bitcast::I32ToF32 | Bitcast::I64ToF32 => {
3124            *need_math = true;
3125            format!("math.Float32frombits(uint32({op}))")
3126        }
3127        Bitcast::F32ToI32 => {
3128            *need_math = true;
3129            format!("int32(math.Float32bits({op}))")
3130        }
3131        Bitcast::F32ToI64 => {
3132            *need_math = true;
3133            format!("int64(math.Float32bits({op}))")
3134        }
3135        Bitcast::I64ToF64 => {
3136            *need_math = true;
3137            format!("math.Float64frombits(uint64({op}))")
3138        }
3139        Bitcast::F64ToI64 => {
3140            *need_math = true;
3141            format!("int64(math.Float64bits({op}))")
3142        }
3143        Bitcast::I32ToI64 | Bitcast::LToI64 => {
3144            format!("int64({op})")
3145        }
3146        Bitcast::PToP64 => {
3147            format!("int64({op})")
3148        }
3149        Bitcast::I64ToI32 | Bitcast::I64ToL | Bitcast::PToI32 => {
3150            format!("int32({op})")
3151        }
3152        Bitcast::I64ToP64 | Bitcast::P64ToI64 => op.into(),
3153        Bitcast::P64ToP | Bitcast::LToP | Bitcast::I32ToP => {
3154            format!("uintptr({op})")
3155        }
3156        Bitcast::PToL => {
3157            format!("uint32({op})")
3158        }
3159        Bitcast::I32ToL => {
3160            format!("uint32({op})")
3161        }
3162        Bitcast::LToI32 => {
3163            format!("uint32({op})")
3164        }
3165        Bitcast::None => op.to_string(),
3166        Bitcast::Sequence(sequence) => {
3167            let [first, second] = &**sequence;
3168            let inner = cast(op, first, need_math);
3169            cast(&inner, second, need_math)
3170        }
3171    }
3172}
3173
3174fn any(resolve: &Resolve, ty: Type, fun: &dyn Fn(Type) -> bool) -> bool {
3175    if fun(ty) {
3176        return true;
3177    }
3178
3179    match ty {
3180        Type::Bool
3181        | Type::U8
3182        | Type::S8
3183        | Type::U16
3184        | Type::S16
3185        | Type::U32
3186        | Type::S32
3187        | Type::U64
3188        | Type::S64
3189        | Type::F32
3190        | Type::F64
3191        | Type::Char
3192        | Type::String => false,
3193        Type::Id(id) => {
3194            let ty = &resolve.types[id];
3195            match &ty.kind {
3196                TypeDefKind::Flags(_) | TypeDefKind::Enum(_) | TypeDefKind::Resource => false,
3197                TypeDefKind::Handle(Handle::Own(resource) | Handle::Borrow(resource)) => {
3198                    any(resolve, Type::Id(*resource), fun)
3199                }
3200                TypeDefKind::Record(record) => record
3201                    .fields
3202                    .iter()
3203                    .any(|field| any(resolve, field.ty, fun)),
3204                TypeDefKind::Variant(variant) => variant
3205                    .cases
3206                    .iter()
3207                    .any(|case| case.ty.map(|ty| any(resolve, ty, fun)).unwrap_or(false)),
3208                TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
3209                    any(resolve, *ty, fun)
3210                }
3211                TypeDefKind::Result(result) => result
3212                    .ok
3213                    .map(|ty| any(resolve, ty, fun))
3214                    .or_else(|| result.err.map(|ty| any(resolve, ty, fun)))
3215                    .unwrap_or(false),
3216                TypeDefKind::Tuple(tuple) => tuple.types.iter().any(|ty| any(resolve, *ty, fun)),
3217                TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => {
3218                    ty.map(|ty| any(resolve, ty, fun)).unwrap_or(false)
3219                }
3220                TypeDefKind::Map(key, value) => {
3221                    any(resolve, *key, fun) || any(resolve, *value, fun)
3222                }
3223                _ => todo!("{:?}", ty.kind),
3224            }
3225        }
3226        _ => todo!("{ty:?}"),
3227    }
3228}
3229
3230fn func_declaration(resolve: &Resolve, func: &Function) -> (String, bool) {
3231    match &func.kind {
3232        FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
3233            (func.item_name().to_upper_camel_case(), false)
3234        }
3235        FunctionKind::Constructor(ty) => {
3236            let ty = resolve.types[*ty]
3237                .name
3238                .as_ref()
3239                .unwrap()
3240                .to_upper_camel_case();
3241            (format!("Make{ty}"), false)
3242        }
3243        FunctionKind::Method(ty) | FunctionKind::AsyncMethod(ty) => {
3244            let ty = resolve.types[*ty]
3245                .name
3246                .as_ref()
3247                .unwrap()
3248                .to_upper_camel_case();
3249            let camel = func.item_name().to_upper_camel_case();
3250            (format!("(self *{ty}) {camel}"), true)
3251        }
3252        FunctionKind::Static(ty) | FunctionKind::AsyncStatic(ty) => {
3253            let ty = resolve.types[*ty]
3254                .name
3255                .as_ref()
3256                .unwrap()
3257                .to_upper_camel_case();
3258            let camel = func.item_name().to_upper_camel_case();
3259            (format!("{ty}{camel}"), false)
3260        }
3261    }
3262}
3263
3264fn maybe_gofmt<'a>(format: Format, code: &'a [u8]) -> Cow<'a, [u8]> {
3265    thread::scope(|s| {
3266        if let Format::True = format
3267            && let Ok((reader, mut writer)) = io::pipe()
3268        {
3269            s.spawn(move || {
3270                _ = writer.write_all(code);
3271            });
3272
3273            if let Ok(output) = Command::new("gofmt").stdin(reader).output()
3274                && output.status.success()
3275            {
3276                return Cow::Owned(output.stdout);
3277            }
3278        }
3279
3280        Cow::Borrowed(code)
3281    })
3282}