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!(
1330                        "{PINNER} := &runtime.Pinner{{}}
1331                    defer {PINNER}.Unpin()"
1332                    )
1333                } else {
1334                    String::new()
1335                },
1336                format!(
1337                    "
1338
1339//go:wasmexport [callback]{prefix}{export_name}
1340func wasm_export_callback_{name}(event0 uint32, event1 uint32, event2 uint32) uint32 {{
1341        return witAsync.Callback(event0, event1, event2)
1342}}
1343
1344//go:wasmimport [export]{module} [task-return]{function}
1345func wasm_export_task_return_{name}({task_return_params})
1346"
1347                ),
1348                "return int32(witAsync.Run(func() {",
1349                "}))",
1350            )
1351        } else if abi::guest_export_needs_post_return(resolve, func) {
1352            (
1353                format!("{PINNER} := &{SYNC_EXPORT_PINNER}"),
1354                format!(
1355                    "
1356
1357//go:wasmexport cabi_post_{export_name}
1358func wasm_export_post_return_{name}(result {results}) {{
1359        syncExportPinner.Unpin()
1360}}
1361"
1362                ),
1363                "",
1364                "",
1365            )
1366        } else {
1367            (String::new(), String::new(), "", "")
1368        };
1369
1370        if self.opts.generate_stubs {
1371            let (camel, has_self) = func_declaration(resolve, func);
1372
1373            let mut imports = BTreeSet::new();
1374            let params =
1375                self.func_params(resolve, func, interface, false, &mut imports, has_self, "_");
1376            let results = self.func_results(resolve, func, interface, false, &mut imports);
1377
1378            self.export_interfaces
1379                .entry(self.interface_name(resolve, interface))
1380                .or_default()
1381                .extend(InterfaceData {
1382                    code: format!(
1383                        r#"
1384func {camel}({params}) {results} {{
1385        panic("not implemented")
1386}}
1387"#
1388                    ),
1389                    imports,
1390                    ..InterfaceData::default()
1391                });
1392        }
1393
1394        format!(
1395            "
1396//go:wasmexport {prefix}{export_name}
1397func wasm_export_{name}({params}) {results} {{
1398        {start}
1399        {pinner}
1400        {code}
1401        {end}
1402}}{other}
1403"
1404        )
1405    }
1406
1407    #[expect(clippy::too_many_arguments, reason = "required context for codegen")]
1408    fn func_params(
1409        &mut self,
1410        resolve: &Resolve,
1411        func: &Function,
1412        interface: Option<&WorldKey>,
1413        in_import: bool,
1414        imports: &mut BTreeSet<String>,
1415        has_self: bool,
1416        prefix: &str,
1417    ) -> String {
1418        func.params
1419            .iter()
1420            .skip(if has_self { 1 } else { 0 })
1421            .map(|Param { name, ty, .. }| {
1422                let name = name.to_lower_camel_case();
1423                let ty = self.type_name(resolve, *ty, interface, in_import, imports);
1424                format!("{prefix}{name} {ty}")
1425            })
1426            .collect::<Vec<_>>()
1427            .join(", ")
1428    }
1429
1430    fn func_results(
1431        &mut self,
1432        resolve: &Resolve,
1433        func: &Function,
1434        interface: Option<&WorldKey>,
1435        in_import: bool,
1436        imports: &mut BTreeSet<String>,
1437    ) -> String {
1438        if let Some(ty) = &func.result {
1439            if let Type::Id(id) = ty
1440                && let TypeDefKind::Tuple(tuple) = &resolve.types[*id].kind
1441            {
1442                let types = tuple
1443                    .types
1444                    .iter()
1445                    .map(|ty| self.type_name(resolve, *ty, interface, in_import, imports))
1446                    .collect::<Vec<_>>()
1447                    .join(", ");
1448                format!("({types})")
1449            } else {
1450                self.type_name(resolve, *ty, interface, in_import, imports)
1451            }
1452        } else {
1453            String::new()
1454        }
1455    }
1456
1457    fn visit_futures_and_streams(
1458        &mut self,
1459        in_import: bool,
1460        resolve: &Resolve,
1461        func: &Function,
1462        interface: Option<&WorldKey>,
1463    ) {
1464        for (index, ty) in func
1465            .find_futures_and_streams(resolve)
1466            .into_iter()
1467            .enumerate()
1468        {
1469            let payload_type = match &resolve.types[ty].kind {
1470                TypeDefKind::Future(ty) => {
1471                    self.need_future = true;
1472                    ty
1473                }
1474                TypeDefKind::Stream(ty) => {
1475                    self.need_stream = true;
1476                    ty
1477                }
1478                _ => unreachable!(),
1479            };
1480
1481            let exported = payload_type
1482                .map(|ty| self.has_exported_resource(resolve, ty))
1483                .unwrap_or(false);
1484
1485            if let hash_map::Entry::Vacant(e) = self.futures_and_streams.entry((ty, exported)) {
1486                e.insert(interface.cloned());
1487
1488                let data = self.future_or_stream(
1489                    resolve,
1490                    ty,
1491                    index,
1492                    in_import,
1493                    in_import || !exported,
1494                    interface,
1495                    &func.name,
1496                );
1497
1498                let name = self.interface_name(resolve, interface);
1499                if in_import || !exported {
1500                    &mut self.interfaces
1501                } else {
1502                    &mut self.export_interfaces
1503                }
1504                .entry(name)
1505                .or_default()
1506                .extend(data);
1507            }
1508        }
1509    }
1510
1511    fn has_exported_resource(&self, resolve: &Resolve, ty: Type) -> bool {
1512        any(resolve, ty, &|ty| {
1513            if let Type::Id(id) = ty
1514                && let TypeDefKind::Resource = &resolve.types[id].kind
1515                && let Direction::Export = self.resources.get(&id).unwrap()
1516            {
1517                true
1518            } else {
1519                false
1520            }
1521        })
1522    }
1523
1524    fn interface_name(&self, resolve: &Resolve, interface: Option<&WorldKey>) -> String {
1525        match interface {
1526            Some(WorldKey::Name(name)) => name.to_snake_case(),
1527            Some(WorldKey::Interface(id)) => {
1528                let interface = &resolve.interfaces[*id];
1529                let package = &resolve.packages[interface.package.unwrap()];
1530                let package_has_multiple_versions = resolve.packages.iter().any(|(_, p)| {
1531                    p.name.namespace == package.name.namespace
1532                        && p.name.name == package.name.name
1533                        && p.name.version != package.name.version
1534                });
1535                let version = if package_has_multiple_versions || self.opts.include_versions {
1536                    if let Some(version) = &package.name.version {
1537                        format!("{}_", version.to_string().replace(['.', '-', '+'], "_"))
1538                    } else {
1539                        String::new()
1540                    }
1541                } else {
1542                    String::new()
1543                };
1544                let namespace = package.name.namespace.to_snake_case();
1545                let package = package.name.name.to_snake_case();
1546                let interface = interface.name.as_ref().unwrap().to_snake_case();
1547                format!("{namespace}_{package}_{version}{interface}")
1548            }
1549            None => "wit_world".into(),
1550        }
1551    }
1552
1553    fn func_name(
1554        &self,
1555        resolve: &Resolve,
1556        interface: Option<&WorldKey>,
1557        func: &Function,
1558    ) -> String {
1559        let prefix = self.interface_name(resolve, interface);
1560        let name = func.name.to_snake_case().replace('.', "_");
1561
1562        format!("{prefix}_{name}")
1563    }
1564}
1565
1566struct FunctionGenerator<'a> {
1567    generator: &'a mut Go,
1568    name: Option<&'a str>,
1569    interface: Option<&'a WorldKey>,
1570    interface_for_types: Option<&'a WorldKey>,
1571    function_to_call: &'a str,
1572    param_names: Vec<String>,
1573    unpin_params: bool,
1574    in_import: bool,
1575    locals: Ns,
1576    src: String,
1577    block_storage: Vec<String>,
1578    blocks: Vec<(String, Vec<String>)>,
1579    need_unsafe: bool,
1580    need_pinner: bool,
1581    need_math: bool,
1582    collect_lifters: bool,
1583    lifter_count: u32,
1584    return_area_size: ArchitectureSize,
1585    return_area_align: Alignment,
1586    imports: BTreeSet<String>,
1587}
1588
1589impl<'a> FunctionGenerator<'a> {
1590    #[expect(clippy::too_many_arguments, reason = "required context for codegen")]
1591    fn new(
1592        generator: &'a mut Go,
1593        name: Option<&'a str>,
1594        interface: Option<&'a WorldKey>,
1595        interface_for_types: Option<&'a WorldKey>,
1596        function_to_call: &'a str,
1597        param_names: Vec<String>,
1598        unpin_params: bool,
1599        in_import: bool,
1600    ) -> Self {
1601        let mut locals = Ns::default();
1602        for name in &param_names {
1603            locals.insert(name).unwrap();
1604        }
1605
1606        Self {
1607            generator,
1608            name,
1609            interface,
1610            interface_for_types,
1611            function_to_call,
1612            param_names,
1613            unpin_params,
1614            in_import,
1615            locals,
1616            src: String::new(),
1617            block_storage: Vec::new(),
1618            blocks: Vec::new(),
1619            need_unsafe: false,
1620            need_pinner: false,
1621            need_math: false,
1622            collect_lifters: false,
1623            lifter_count: 0,
1624            return_area_size: ArchitectureSize::default(),
1625            return_area_align: Alignment::default(),
1626            imports: BTreeSet::new(),
1627        }
1628    }
1629
1630    fn type_name(&mut self, resolve: &Resolve, ty: Type) -> String {
1631        self.generator.type_name(
1632            resolve,
1633            ty,
1634            self.interface_for_types,
1635            self.in_import,
1636            &mut self.imports,
1637        )
1638    }
1639
1640    fn package_for_owner(
1641        &mut self,
1642        resolve: &Resolve,
1643        owner: Option<&WorldKey>,
1644        ty: TypeId,
1645    ) -> String {
1646        self.generator.package_for_owner(
1647            resolve,
1648            owner,
1649            ty,
1650            self.interface_for_types,
1651            self.in_import,
1652            &mut self.imports,
1653        )
1654    }
1655}
1656
1657impl Bindgen for FunctionGenerator<'_> {
1658    type Operand = String;
1659
1660    fn sizes(&self) -> &SizeAlign {
1661        &self.generator.sizes
1662    }
1663
1664    fn push_block(&mut self) {
1665        let prev = mem::take(&mut self.src);
1666        self.block_storage.push(prev);
1667    }
1668
1669    fn finish_block(&mut self, operands: &mut Vec<String>) {
1670        let to_restore = self.block_storage.pop().unwrap();
1671        let src = mem::replace(&mut self.src, to_restore);
1672        self.blocks.push((src, mem::take(operands)));
1673    }
1674
1675    fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String {
1676        if self.in_import {
1677            self.return_area_size = self.return_area_size.max(size);
1678            self.return_area_align = self.return_area_align.max(align);
1679
1680            if !self.return_area_size.is_empty() {
1681                self.need_pinner = true;
1682                self.imports.insert(remote_pkg("runtime"));
1683            }
1684
1685            IMPORT_RETURN_AREA.into()
1686        } else {
1687            self.generator.return_area_size = self.generator.return_area_size.max(size);
1688            self.generator.return_area_align = self.generator.return_area_align.max(align);
1689            EXPORT_RETURN_AREA.into()
1690        }
1691    }
1692
1693    fn is_list_canonical(&self, _: &Resolve, ty: &Type) -> bool {
1694        matches!(
1695            ty,
1696            Type::U8
1697                | Type::S8
1698                | Type::U16
1699                | Type::S16
1700                | Type::U32
1701                | Type::S32
1702                | Type::U64
1703                | Type::S64
1704                | Type::F32
1705                | Type::F64
1706        )
1707    }
1708
1709    fn emit(
1710        &mut self,
1711        resolve: &Resolve,
1712        instruction: &Instruction<'_>,
1713        operands: &mut Vec<String>,
1714        results: &mut Vec<String>,
1715    ) {
1716        let store = |me: &mut Self, src, pointer, offset: &ArchitectureSize, ty| {
1717            me.need_unsafe = true;
1718            let offset = offset.format(POINTER_SIZE_EXPRESSION);
1719            uwriteln!(
1720                me.src,
1721                "*(*{ty})(unsafe.Add(unsafe.Pointer({pointer}), {offset})) = {src}"
1722            );
1723        };
1724        let load = |me: &mut Self,
1725                    results: &mut Vec<String>,
1726                    pointer,
1727                    offset: &ArchitectureSize,
1728                    ty,
1729                    cast: &dyn Fn(String) -> String| {
1730            me.need_unsafe = true;
1731            let offset = offset.format(POINTER_SIZE_EXPRESSION);
1732            results.push(cast(format!(
1733                "*(*{ty})(unsafe.Add(unsafe.Pointer({pointer}), {offset}))"
1734            )));
1735        };
1736
1737        match instruction {
1738            Instruction::GetArg { nth } => results.push(self.param_names[*nth].clone()),
1739            Instruction::StringLower { .. } => {
1740                self.need_pinner = true;
1741                self.need_unsafe = true;
1742                let string = &operands[0];
1743                let utf8 = self.locals.tmp("utf8");
1744                uwriteln!(
1745                    self.src,
1746                    "{utf8} := unsafe.Pointer(unsafe.StringData({string}))\n\
1747                     {PINNER}.Pin({utf8})"
1748                );
1749                results.push(format!("uintptr({utf8})"));
1750                results.push(format!("uint32(len({string}))"));
1751            }
1752            Instruction::StringLift { .. } => {
1753                self.need_unsafe = true;
1754                let pointer = &operands[0];
1755                let length = &operands[1];
1756                let value = self.locals.tmp("value");
1757                uwriteln!(
1758                    self.src,
1759                    "{value} := unsafe.String((*uint8)(unsafe.Pointer({pointer})), {length})"
1760                );
1761                results.push(value)
1762            }
1763            Instruction::ListCanonLower { .. } => {
1764                self.need_pinner = true;
1765                self.need_unsafe = true;
1766                let slice = &operands[0];
1767                let data = self.locals.tmp("data");
1768                uwriteln!(
1769                    self.src,
1770                    "{data} := unsafe.Pointer(unsafe.SliceData({slice}))\n\
1771                     {PINNER}.Pin({data})"
1772                );
1773                results.push(format!("uintptr({data})"));
1774                results.push(format!("uint32(len({slice}))"));
1775            }
1776            Instruction::ListCanonLift { element, .. } => {
1777                self.need_unsafe = true;
1778                let pointer = &operands[0];
1779                let length = &operands[1];
1780                let ty = self.type_name(resolve, **element);
1781                let value = self.locals.tmp("value");
1782                uwriteln!(
1783                    self.src,
1784                    "{value} := unsafe.Slice((*{ty})(unsafe.Pointer({pointer})), {length})"
1785                );
1786                results.push(value)
1787            }
1788            Instruction::ListLower { element, .. } => {
1789                self.need_unsafe = true;
1790                self.need_pinner = true;
1791                self.imports.insert(remote_pkg("runtime"));
1792                let (body, _) = self.blocks.pop().unwrap();
1793                let value = &operands[0];
1794                let slice = self.locals.tmp("slice");
1795                let result = self.locals.tmp("result");
1796                let length = self.locals.tmp("length");
1797                let size = self
1798                    .generator
1799                    .sizes
1800                    .size(element)
1801                    .format(POINTER_SIZE_EXPRESSION);
1802                let align = self
1803                    .generator
1804                    .sizes
1805                    .align(element)
1806                    .format(POINTER_SIZE_EXPRESSION);
1807                uwriteln!(
1808                    self.src,
1809                    "{slice} := {value}
1810{length} := uint32(len({slice}))
1811{result} := witRuntime.Allocate({PINNER}, uintptr({length} * {size}), {align})
1812for index, {ITER_ELEMENT} := range {slice} {{
1813        {ITER_BASE_POINTER} := unsafe.Add({result}, index * {size})
1814        {body}
1815}}
1816"
1817                );
1818                results.push(format!("uintptr({result})"));
1819                results.push(length);
1820            }
1821            Instruction::ListLift { element, .. } => {
1822                self.need_unsafe = true;
1823                let (body, body_results) = self.blocks.pop().unwrap();
1824                let value = &operands[0];
1825                let length = &operands[1];
1826                let result = self.locals.tmp("result");
1827                let size = self
1828                    .generator
1829                    .sizes
1830                    .size(element)
1831                    .format(POINTER_SIZE_EXPRESSION);
1832                let element_type = self.type_name(resolve, **element);
1833                let body_result = &body_results[0];
1834                uwriteln!(
1835                    self.src,
1836                    "{result} := make([]{element_type}, 0, {length})
1837for index := 0; index < int({length}); index++ {{
1838        {ITER_BASE_POINTER} := unsafe.Add(unsafe.Pointer({value}), index * {size})
1839        {body}
1840        {result} = append({result}, {body_result})
1841}}
1842"
1843                );
1844                results.push(result);
1845            }
1846            Instruction::CallInterface { func, .. } => {
1847                if self.unpin_params {
1848                    self.imports.insert(remote_pkg("runtime"));
1849                    uwriteln!(self.src, "witRuntime.Unpin()");
1850                }
1851
1852                let name = func.item_name().to_upper_camel_case();
1853                let package = format!(
1854                    "export_{}",
1855                    self.generator.interface_name(resolve, self.interface)
1856                );
1857
1858                let call = match &func.kind {
1859                    FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
1860                        let args = operands.join(", ");
1861                        let call = format!("{package}.{name}({args})");
1862                        self.imports.insert(self.generator.mod_pkg(true, &package));
1863                        call
1864                    }
1865                    FunctionKind::Constructor(ty) => {
1866                        let args = operands.join(", ");
1867                        let ty = resolve.types[*ty]
1868                            .name
1869                            .as_ref()
1870                            .unwrap()
1871                            .to_upper_camel_case();
1872                        let call = format!("{package}.Make{ty}({args})");
1873                        self.imports.insert(self.generator.mod_pkg(true, &package));
1874                        call
1875                    }
1876                    FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) => {
1877                        let target = &operands[0];
1878                        let args = operands[1..].join(", ");
1879                        format!("({target}).{name}({args})")
1880                    }
1881                    FunctionKind::Static(ty) | FunctionKind::AsyncStatic(ty) => {
1882                        let args = operands.join(", ");
1883                        let ty = self.type_name(resolve, Type::Id(*ty));
1884                        format!("{ty}{name}({args})")
1885                    }
1886                };
1887
1888                if let Some(ty) = func.result {
1889                    let result = self.locals.tmp("result");
1890                    if let Type::Id(ty) = ty
1891                        && let TypeDefKind::Tuple(tuple) = &resolve.types[ty].kind
1892                    {
1893                        let count = tuple.types.len();
1894                        self.generator.tuples.insert(count);
1895                        self.imports.insert(remote_pkg("types"));
1896
1897                        let results = (0..count)
1898                            .map(|_| self.locals.tmp("result"))
1899                            .collect::<Vec<_>>()
1900                            .join(", ");
1901
1902                        let types = tuple
1903                            .types
1904                            .iter()
1905                            .map(|&ty| self.type_name(resolve, ty))
1906                            .collect::<Vec<_>>()
1907                            .join(", ");
1908
1909                        uwriteln!(
1910                            self.src,
1911                            "{results} := {call}
1912{result} := witTypes.Tuple{count}[{types}]{{{results}}}"
1913                        );
1914                    } else {
1915                        uwriteln!(self.src, "{result} := {call}");
1916                    }
1917                    results.push(result);
1918                } else {
1919                    uwriteln!(self.src, "{call}");
1920                }
1921            }
1922            Instruction::Return { func, .. } => {
1923                if let Some(ty) = func.result {
1924                    let result = &operands[0];
1925                    if self.in_import
1926                        && let Type::Id(ty) = ty
1927                        && let TypeDefKind::Tuple(tuple) = &resolve.types[ty].kind
1928                    {
1929                        let count = tuple.types.len();
1930                        let tuple = self.locals.tmp("tuple");
1931
1932                        let results = (0..count)
1933                            .map(|index| format!("{tuple}.F{index}"))
1934                            .collect::<Vec<_>>()
1935                            .join(", ");
1936
1937                        uwriteln!(
1938                            self.src,
1939                            "{tuple} := {result}
1940return {results}"
1941                        );
1942                    } else {
1943                        uwriteln!(self.src, "return {result}");
1944                    }
1945                }
1946            }
1947            Instruction::AsyncTaskReturn { .. } => {
1948                let name = self.name.unwrap();
1949                let args = operands.join(", ");
1950                uwriteln!(self.src, "wasm_export_task_return_{name}({args})");
1951            }
1952            Instruction::LengthStore { offset } => store(
1953                self,
1954                &format!("uint32({})", operands[0]),
1955                &operands[1],
1956                offset,
1957                "uint32",
1958            ),
1959            Instruction::PointerStore { offset } => store(
1960                self,
1961                &format!("uint32(uintptr({}))", operands[0]),
1962                &operands[1],
1963                offset,
1964                "uint32",
1965            ),
1966            Instruction::I32Store8 { offset } => store(
1967                self,
1968                &format!("int8({})", operands[0]),
1969                &operands[1],
1970                offset,
1971                "int8",
1972            ),
1973            Instruction::I32Store16 { offset } => store(
1974                self,
1975                &format!("int16({})", operands[0]),
1976                &operands[1],
1977                offset,
1978                "int16",
1979            ),
1980            Instruction::I32Store { offset } => {
1981                store(self, &operands[0], &operands[1], offset, "int32")
1982            }
1983            Instruction::I64Store { offset } => {
1984                store(self, &operands[0], &operands[1], offset, "int64")
1985            }
1986            Instruction::F32Store { offset } => {
1987                store(self, &operands[0], &operands[1], offset, "float32")
1988            }
1989            Instruction::F64Store { offset } => {
1990                store(self, &operands[0], &operands[1], offset, "float64")
1991            }
1992            Instruction::LengthLoad { offset } => {
1993                load(self, results, &operands[0], offset, "uint32", &|v| v)
1994            }
1995            Instruction::PointerLoad { offset } => {
1996                load(self, results, &operands[0], offset, "uint32", &|v| {
1997                    format!("uintptr({v})")
1998                })
1999            }
2000            Instruction::I32Load8U { offset } => {
2001                load(self, results, &operands[0], offset, "uint32", &|v| {
2002                    format!("uint8({v})")
2003                })
2004            }
2005            Instruction::I32Load8S { offset } => {
2006                load(self, results, &operands[0], offset, "uint32", &|v| {
2007                    format!("int8({v})")
2008                })
2009            }
2010            Instruction::I32Load16U { offset } => {
2011                load(self, results, &operands[0], offset, "uint32", &|v| {
2012                    format!("uint16({v})")
2013                })
2014            }
2015            Instruction::I32Load16S { offset } => {
2016                load(self, results, &operands[0], offset, "uint32", &|v| {
2017                    format!("int16({v})")
2018                })
2019            }
2020            Instruction::I32Load { offset } => {
2021                load(self, results, &operands[0], offset, "int32", &|v| v)
2022            }
2023            Instruction::I64Load { offset } => {
2024                load(self, results, &operands[0], offset, "int64", &|v| v)
2025            }
2026            Instruction::F32Load { offset } => {
2027                load(self, results, &operands[0], offset, "float32", &|v| v)
2028            }
2029            Instruction::F64Load { offset } => {
2030                load(self, results, &operands[0], offset, "float64", &|v| v)
2031            }
2032            Instruction::BoolFromI32 => results.push(format!("({} != 0)", operands[0])),
2033            Instruction::U8FromI32 => results.push(format!("uint8({})", operands[0])),
2034            Instruction::S8FromI32 => results.push(format!("int8({})", operands[0])),
2035            Instruction::U16FromI32 => results.push(format!("uint16({})", operands[0])),
2036            Instruction::S16FromI32 => results.push(format!("int16({})", operands[0])),
2037            Instruction::U32FromI32 => results.push(format!("uint32({})", operands[0])),
2038            Instruction::S32FromI32 | Instruction::S64FromI64 => {
2039                results.push(operands.pop().unwrap())
2040            }
2041            Instruction::U64FromI64 => results.push(format!("uint64({})", operands[0])),
2042            Instruction::I32FromBool => {
2043                let value = &operands[0];
2044                let result = self.locals.tmp("result");
2045                uwriteln!(
2046                    self.src,
2047                    "var {result} int32
2048if {value} {{
2049        {result} = 1
2050}} else {{
2051        {result} = 0
2052}}"
2053                );
2054                results.push(result);
2055            }
2056            Instruction::I32FromU8
2057            | Instruction::I32FromS8
2058            | Instruction::I32FromU16
2059            | Instruction::I32FromS16
2060            | Instruction::I32FromU32 => {
2061                results.push(format!("int32({})", operands[0]));
2062            }
2063            Instruction::I32FromS32 | Instruction::I64FromS64 => {
2064                results.push(operands.pop().unwrap())
2065            }
2066            Instruction::I64FromU64 => results.push(format!("int64({})", operands[0])),
2067            Instruction::CoreF32FromF32
2068            | Instruction::CoreF64FromF64
2069            | Instruction::F32FromCoreF32
2070            | Instruction::F64FromCoreF64 => results.push(operands.pop().unwrap()),
2071            Instruction::CharFromI32 => results.push(format!("rune({})", operands[0])),
2072            Instruction::I32FromChar => results.push(format!("int32({})", operands[0])),
2073            Instruction::TupleLower { tuple, .. } => {
2074                let op = &operands[0];
2075                for index in 0..tuple.types.len() {
2076                    results.push(format!("({op}).F{index}"));
2077                }
2078            }
2079            Instruction::TupleLift { tuple, .. } => {
2080                let count = tuple.types.len();
2081                self.generator.tuples.insert(count);
2082                let types = tuple
2083                    .types
2084                    .iter()
2085                    .map(|&ty| self.type_name(resolve, ty))
2086                    .collect::<Vec<_>>()
2087                    .join(", ");
2088                let fields = operands.join(", ");
2089                self.imports.insert(remote_pkg("types"));
2090                results.push(format!("witTypes.Tuple{count}[{types}]{{{fields}}}"));
2091            }
2092            Instruction::FlagsLower { .. } => {
2093                let value = operands.pop().unwrap();
2094                results.push(format!("int32({value})"))
2095            }
2096            Instruction::FlagsLift { flags, .. } => {
2097                let value = operands.pop().unwrap();
2098                let repr = flags_repr(flags);
2099                results.push(format!("{repr}({value})"))
2100            }
2101            Instruction::RecordLower { record, .. } => {
2102                let op = &operands[0];
2103                for field in &record.fields {
2104                    let field = field.name.to_upper_camel_case();
2105                    results.push(format!("({op}).{field}"));
2106                }
2107            }
2108            Instruction::RecordLift { ty, .. } => {
2109                let name = self.type_name(resolve, Type::Id(*ty));
2110                let fields = operands.join(", ");
2111                results.push(format!("{name}{{{fields}}}"));
2112            }
2113            Instruction::OptionLower {
2114                results: result_types,
2115                ..
2116            } => {
2117                self.generator.need_option = true;
2118                self.imports.insert(remote_pkg("types"));
2119                let (some, some_results) = self.blocks.pop().unwrap();
2120                let (none, none_results) = self.blocks.pop().unwrap();
2121                let value = &operands[0];
2122
2123                let result_names = (0..result_types.len())
2124                    .map(|_| self.locals.tmp("option"))
2125                    .collect::<Vec<_>>();
2126
2127                let declarations = result_types
2128                    .iter()
2129                    .zip(&result_names)
2130                    .map(|(ty, name)| {
2131                        let ty = wasm_type(*ty);
2132                        format!("var {name} {ty}")
2133                    })
2134                    .collect::<Vec<_>>()
2135                    .join("\n");
2136
2137                let some_result_assignments = some_results
2138                    .iter()
2139                    .zip(&result_names)
2140                    .map(|(result, name)| format!("{name} = {result}"))
2141                    .collect::<Vec<_>>()
2142                    .join("\n");
2143
2144                let none_result_assignments = none_results
2145                    .iter()
2146                    .zip(&result_names)
2147                    .map(|(result, name)| format!("{name} = {result}"))
2148                    .collect::<Vec<_>>()
2149                    .join("\n");
2150
2151                results.extend(result_names);
2152
2153                uwriteln!(
2154                    self.src,
2155                    r#"{declarations}
2156switch {value}.Tag() {{
2157case witTypes.OptionNone:
2158        {none}
2159        {none_result_assignments}
2160case witTypes.OptionSome:
2161        {VARIANT_PAYLOAD_NAME} := {value}.Some()
2162        {some}
2163        {some_result_assignments}
2164default:
2165        panic("unreachable")
2166}}"#
2167                );
2168            }
2169            Instruction::OptionLift { ty, payload } => {
2170                self.generator.need_option = true;
2171                self.imports.insert(remote_pkg("types"));
2172                let (some, some_results) = self.blocks.pop().unwrap();
2173                let (none, none_results) = self.blocks.pop().unwrap();
2174                assert!(none_results.is_empty());
2175                assert!(some_results.len() == 1);
2176                let some_result = &some_results[0];
2177                let ty = self.type_name(resolve, Type::Id(*ty));
2178                let some_type = self.type_name(resolve, **payload);
2179                let result = self.locals.tmp("option");
2180                let tag = &operands[0];
2181                uwriteln!(
2182                    self.src,
2183                    r#"var {result} {ty}
2184switch {tag} {{
2185case 0:
2186        {none}
2187        {result} = witTypes.None[{some_type}]()
2188case 1:
2189        {some}
2190        {result} = witTypes.Some[{some_type}]({some_result})
2191default:
2192        panic("unreachable")
2193}}"#
2194                );
2195                results.push(result);
2196            }
2197            Instruction::ResultLower {
2198                result,
2199                results: result_types,
2200                ..
2201            } => {
2202                self.generator.need_result = true;
2203                self.imports.insert(remote_pkg("types"));
2204                let (err, err_results) = self.blocks.pop().unwrap();
2205                let (ok, ok_results) = self.blocks.pop().unwrap();
2206                let value = &operands[0];
2207
2208                let result_names = (0..result_types.len())
2209                    .map(|_| self.locals.tmp("option"))
2210                    .collect::<Vec<_>>();
2211
2212                let declarations = result_types
2213                    .iter()
2214                    .zip(&result_names)
2215                    .map(|(ty, name)| {
2216                        let ty = wasm_type(*ty);
2217                        format!("var {name} {ty}")
2218                    })
2219                    .collect::<Vec<_>>()
2220                    .join("\n");
2221
2222                let ok_result_assignments = ok_results
2223                    .iter()
2224                    .zip(&result_names)
2225                    .map(|(result, name)| format!("{name} = {result}"))
2226                    .collect::<Vec<_>>()
2227                    .join("\n");
2228
2229                let err_result_assignments = err_results
2230                    .iter()
2231                    .zip(&result_names)
2232                    .map(|(result, name)| format!("{name} = {result}"))
2233                    .collect::<Vec<_>>()
2234                    .join("\n");
2235
2236                results.extend(result_names);
2237
2238                let ok_set_payload = if result.ok.is_some() {
2239                    format!("{VARIANT_PAYLOAD_NAME} := {value}.Ok()")
2240                } else {
2241                    self.generator.need_unit = true;
2242                    String::new()
2243                };
2244
2245                let err_set_payload = if result.err.is_some() {
2246                    format!("{VARIANT_PAYLOAD_NAME} := {value}.Err()")
2247                } else {
2248                    self.generator.need_unit = true;
2249                    String::new()
2250                };
2251
2252                uwriteln!(
2253                    self.src,
2254                    r#"{declarations}
2255switch {value}.Tag() {{
2256case witTypes.ResultOk:
2257        {ok_set_payload}
2258        {ok}
2259        {ok_result_assignments}
2260case witTypes.ResultErr:
2261        {err_set_payload}
2262        {err}
2263        {err_result_assignments}
2264default:
2265        panic("unreachable")
2266}}"#
2267                );
2268            }
2269            Instruction::ResultLift { ty, result, .. } => {
2270                self.generator.need_result = true;
2271                self.imports.insert(remote_pkg("types"));
2272                let (err, err_results) = self.blocks.pop().unwrap();
2273                let (ok, ok_results) = self.blocks.pop().unwrap();
2274                assert_eq!(ok_results.is_empty(), result.ok.is_none());
2275                assert_eq!(err_results.is_empty(), result.err.is_none());
2276                let ok_result = if result.ok.is_some() {
2277                    &ok_results[0]
2278                } else {
2279                    self.generator.need_unit = true;
2280                    "witTypes.Unit{}"
2281                };
2282                let err_result = if result.err.is_some() {
2283                    &err_results[0]
2284                } else {
2285                    self.generator.need_unit = true;
2286                    "witTypes.Unit{}"
2287                };
2288                let ty = self.type_name(resolve, Type::Id(*ty));
2289                let ok_type = result
2290                    .ok
2291                    .map(|ty| self.type_name(resolve, ty))
2292                    .unwrap_or_else(|| {
2293                        self.generator.need_unit = true;
2294                        "witTypes.Unit".into()
2295                    });
2296                let err_type = result
2297                    .err
2298                    .map(|ty| self.type_name(resolve, ty))
2299                    .unwrap_or_else(|| {
2300                        self.generator.need_unit = true;
2301                        "witTypes.Unit".into()
2302                    });
2303                let result = self.locals.tmp("result");
2304                let tag = &operands[0];
2305                uwriteln!(
2306                    self.src,
2307                    r#"var {result} {ty}
2308switch {tag} {{
2309case 0:
2310        {ok}
2311        {result} = witTypes.Ok[{ok_type}, {err_type}]({ok_result})
2312case 1:
2313        {err}
2314        {result} = witTypes.Err[{ok_type}, {err_type}]({err_result})
2315default:
2316        panic("unreachable")
2317}}"#
2318                );
2319                results.push(result);
2320            }
2321            Instruction::EnumLower { .. } => results.push(format!("int32({})", operands[0])),
2322            Instruction::EnumLift { enum_, .. } => {
2323                results.push(format!("{}({})", int_repr(enum_.tag()), operands[0]))
2324            }
2325            Instruction::VariantLower {
2326                ty,
2327                variant,
2328                results: result_types,
2329                ..
2330            } => {
2331                let blocks = self
2332                    .blocks
2333                    .drain(self.blocks.len() - variant.cases.len()..)
2334                    .collect::<Vec<_>>();
2335
2336                let ty = self.type_name(resolve, Type::Id(*ty));
2337                let value = &operands[0];
2338
2339                let result_names = (0..result_types.len())
2340                    .map(|_| self.locals.tmp("variant"))
2341                    .collect::<Vec<_>>();
2342
2343                let declarations = result_types
2344                    .iter()
2345                    .zip(&result_names)
2346                    .map(|(ty, name)| {
2347                        let ty = wasm_type(*ty);
2348                        format!("var {name} {ty}")
2349                    })
2350                    .collect::<Vec<_>>()
2351                    .join("\n");
2352
2353                let cases = variant
2354                    .cases
2355                    .iter()
2356                    .zip(blocks)
2357                    .map(|(case, (block, block_results))| {
2358                        let assignments = result_names
2359                            .iter()
2360                            .zip(&block_results)
2361                            .map(|(name, result)| format!("{name} = {result}"))
2362                            .collect::<Vec<_>>()
2363                            .join("\n");
2364
2365                        let name = case.name.to_upper_camel_case();
2366
2367                        let set_payload = if case.ty.is_some() {
2368                            format!("{VARIANT_PAYLOAD_NAME} := {value}.{name}()")
2369                        } else {
2370                            String::new()
2371                        };
2372
2373                        format!(
2374                            "case {ty}{name}:
2375        {set_payload}
2376        {block}
2377        {assignments}
2378"
2379                        )
2380                    })
2381                    .collect::<Vec<_>>()
2382                    .join("\n");
2383
2384                results.extend(result_names);
2385
2386                uwriteln!(
2387                    self.src,
2388                    r#"{declarations}
2389switch {value}.Tag() {{
2390{cases}
2391default:
2392        panic("unreachable")
2393}}"#
2394                );
2395            }
2396            Instruction::VariantLift { ty, variant, .. } => {
2397                let blocks = self
2398                    .blocks
2399                    .drain(self.blocks.len() - variant.cases.len()..)
2400                    .collect::<Vec<_>>();
2401
2402                let ty = self.type_name(resolve, Type::Id(*ty));
2403                let result = self.locals.tmp("variant");
2404                let tag = &operands[0];
2405
2406                let (package, name) = if let Some(index) = ty.find('.') {
2407                    (&ty[..index + 1], &ty[index + 1..])
2408                } else {
2409                    ("", ty.as_str())
2410                };
2411
2412                let cases = variant
2413                    .cases
2414                    .iter()
2415                    .zip(blocks)
2416                    .enumerate()
2417                    .map(|(index, (case, (block, block_results)))| {
2418                        assert_eq!(block_results.is_empty(), case.ty.is_none());
2419                        let payload = if case.ty.is_some() {
2420                            &block_results[0]
2421                        } else {
2422                            ""
2423                        };
2424                        let case = case.name.to_upper_camel_case();
2425                        format!(
2426                            "case {index}:
2427        {block}
2428        {result} = {package}Make{name}{case}({payload})
2429"
2430                        )
2431                    })
2432                    .collect::<Vec<_>>()
2433                    .join("\n");
2434
2435                uwriteln!(
2436                    self.src,
2437                    r#"var {result} {ty}
2438switch {tag} {{
2439{cases}
2440default:
2441        panic("unreachable")
2442}}"#
2443                );
2444                results.push(result);
2445            }
2446            Instruction::VariantPayloadName => results.push(VARIANT_PAYLOAD_NAME.into()),
2447            Instruction::IterElem { .. } => results.push(ITER_ELEMENT.into()),
2448            Instruction::IterBasePointer => results.push(ITER_BASE_POINTER.into()),
2449            Instruction::I32Const { val } => results.push(format!("int32({val})")),
2450            Instruction::ConstZero { tys } => {
2451                results.extend(iter::repeat_with(|| "0".into()).take(tys.len()));
2452            }
2453            Instruction::Bitcasts { casts } => {
2454                results.extend(
2455                    casts
2456                        .iter()
2457                        .zip(operands)
2458                        .map(|(which, op)| cast(op, which, &mut self.need_math)),
2459                );
2460            }
2461            Instruction::FutureLower { .. }
2462            | Instruction::StreamLower { .. }
2463            | Instruction::HandleLower {
2464                handle: Handle::Own(_),
2465                ..
2466            } => {
2467                let op = &operands[0];
2468                if self.collect_lifters {
2469                    self.lifter_count += 1;
2470                    let resource = self.locals.tmp("resource");
2471                    let handle = self.locals.tmp("handle");
2472                    uwriteln!(
2473                        self.src,
2474                        "{resource} := {op}
2475{handle} := {resource}.TakeHandle()
2476lifters = append(lifters, func() {{
2477        {resource}.SetHandle({handle})
2478}})"
2479                    );
2480                    results.push(handle)
2481                } else {
2482                    results.push(format!("({op}).TakeHandle()"))
2483                }
2484            }
2485            Instruction::HandleLower {
2486                handle: Handle::Borrow(_),
2487                ..
2488            } => results.push(format!("({}).Handle()", operands[0])),
2489            Instruction::HandleLift { handle, .. } => {
2490                let (which, resource) = match handle {
2491                    Handle::Borrow(resource) => ("Borrow", resource),
2492                    Handle::Own(resource) => ("Own", resource),
2493                };
2494                let handle = &operands[0];
2495                let ty = self.type_name(resolve, Type::Id(*resource));
2496                results.push(format!("{ty}From{which}Handle(int32(uintptr({handle})))"))
2497            }
2498            Instruction::CallWasm { sig, .. } => {
2499                let assignment = match &sig.results[..] {
2500                    [] => String::new(),
2501                    [_] => {
2502                        let result = self.locals.tmp("result");
2503                        let assignment = format!("{result} := ");
2504                        results.push(result);
2505                        assignment
2506                    }
2507                    _ => unreachable!(),
2508                };
2509                let name = &self.function_to_call;
2510                let params = operands.join(", ");
2511                uwriteln!(self.src, "{assignment}{name}({params})")
2512            }
2513            Instruction::Flush { amt } => {
2514                for op in operands.iter().take(*amt) {
2515                    let result = self.locals.tmp("result");
2516                    uwriteln!(self.src, "{result} := {op};");
2517                    results.push(result);
2518                }
2519            }
2520            Instruction::FutureLift { ty, .. } => {
2521                let exported = self.generator.has_exported_resource(resolve, Type::Id(*ty));
2522                let owner = self
2523                    .generator
2524                    .futures_and_streams
2525                    .get(&(*ty, exported))
2526                    .unwrap()
2527                    .clone();
2528                let package = self.package_for_owner(resolve, owner.as_ref(), *ty);
2529                let TypeDefKind::Future(payload_ty) = &resolve.types[*ty].kind else {
2530                    unreachable!()
2531                };
2532                let camel = if let Some(ty) = payload_ty {
2533                    self.generator
2534                        .mangle_name(resolve, *ty, owner.as_ref())
2535                        .to_upper_camel_case()
2536                } else {
2537                    "Unit".into()
2538                };
2539                let handle = &operands[0];
2540                results.push(format!("{package}LiftFuture{camel}({handle})"));
2541            }
2542            Instruction::StreamLift { ty, .. } => {
2543                let exported = self.generator.has_exported_resource(resolve, Type::Id(*ty));
2544                let owner = self
2545                    .generator
2546                    .futures_and_streams
2547                    .get(&(*ty, exported))
2548                    .unwrap()
2549                    .clone();
2550                let package = self.package_for_owner(resolve, owner.as_ref(), *ty);
2551                let TypeDefKind::Stream(payload_ty) = &resolve.types[*ty].kind else {
2552                    unreachable!()
2553                };
2554                let camel = if let Some(ty) = payload_ty {
2555                    self.generator
2556                        .mangle_name(resolve, *ty, owner.as_ref())
2557                        .to_upper_camel_case()
2558                } else {
2559                    "Unit".into()
2560                };
2561                let handle = &operands[0];
2562                results.push(format!("{package}LiftStream{camel}({handle})"));
2563            }
2564            Instruction::MapLower { key, value, .. } => {
2565                self.need_unsafe = true;
2566                self.need_pinner = true;
2567                self.imports.insert(remote_pkg("runtime"));
2568                let (body, _) = self.blocks.pop().unwrap();
2569                let value_op = &operands[0];
2570                let src_map = self.locals.tmp("srcMap");
2571                let result = self.locals.tmp("result");
2572                let length = self.locals.tmp("length");
2573                let idx = self.locals.tmp("idx");
2574                let entry = self.generator.sizes.record([*key, *value]);
2575                let size = entry.size.format(POINTER_SIZE_EXPRESSION);
2576                let align = entry.align.format(POINTER_SIZE_EXPRESSION);
2577                uwriteln!(
2578                    self.src,
2579                    "{src_map} := {value_op}
2580{length} := uint32(len({src_map}))
2581{result} := witRuntime.Allocate({PINNER}, uintptr({length} * {size}), {align})
2582var {idx} int
2583for map_key, map_value := range {src_map} {{
2584        {ITER_BASE_POINTER} := unsafe.Add({result}, {idx} * {size})
2585        {body}
2586        {idx}++
2587}}
2588"
2589                );
2590                results.push(format!("uintptr({result})"));
2591                results.push(length);
2592            }
2593            Instruction::MapLift { key, value, .. } => {
2594                self.need_unsafe = true;
2595                let (body, body_results) = self.blocks.pop().unwrap();
2596                let pointer = &operands[0];
2597                let length = &operands[1];
2598                let result = self.locals.tmp("result");
2599                let entry = self.generator.sizes.record([*key, *value]);
2600                let size = entry.size.format(POINTER_SIZE_EXPRESSION);
2601                let key_type = self.type_name(resolve, **key);
2602                let value_type = self.type_name(resolve, **value);
2603                let body_key = &body_results[0];
2604                let body_value = &body_results[1];
2605                uwriteln!(
2606                    self.src,
2607                    "{result} := make(map[{key_type}]{value_type}, {length})
2608for index := 0; index < int({length}); index++ {{
2609        {ITER_BASE_POINTER} := unsafe.Add(unsafe.Pointer({pointer}), index * {size})
2610        {body}
2611        {result}[{body_key}] = {body_value}
2612}}
2613"
2614                );
2615                results.push(result);
2616            }
2617            Instruction::IterMapKey { .. } => results.push("map_key".into()),
2618            Instruction::IterMapValue { .. } => results.push("map_value".into()),
2619            Instruction::GuestDeallocateMap { .. } | Instruction::GuestDeallocate { .. } => {
2620                // Nothing to do here; should be handled when calling `pinner.Unpin()`
2621            }
2622            _ => unimplemented!("{instruction:?}"),
2623        }
2624    }
2625}
2626
2627struct InterfaceGenerator<'a> {
2628    generator: &'a mut Go,
2629    resolve: &'a Resolve,
2630    interface: Option<(InterfaceId, &'a WorldKey)>,
2631    in_import: bool,
2632    src: String,
2633    imports: BTreeSet<String>,
2634    need_unsafe: bool,
2635    need_runtime: bool,
2636}
2637
2638impl<'a> InterfaceGenerator<'a> {
2639    fn new(
2640        generator: &'a mut Go,
2641        resolve: &'a Resolve,
2642        interface: Option<(InterfaceId, &'a WorldKey)>,
2643        in_import: bool,
2644    ) -> Self {
2645        Self {
2646            generator,
2647            resolve,
2648            interface,
2649            in_import,
2650            src: String::new(),
2651            imports: BTreeSet::new(),
2652            need_unsafe: false,
2653            need_runtime: false,
2654        }
2655    }
2656
2657    fn type_name(&mut self, resolve: &Resolve, ty: Type) -> String {
2658        self.generator.type_name(
2659            resolve,
2660            ty,
2661            self.interface.map(|(_, key)| key),
2662            self.in_import || !self.generator.has_exported_resource(resolve, ty),
2663            &mut self.imports,
2664        )
2665    }
2666}
2667
2668impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
2669    fn resolve(&self) -> &'a Resolve {
2670        self.resolve
2671    }
2672
2673    fn type_record(&mut self, _: TypeId, name: &str, record: &Record, docs: &Docs) {
2674        let name = name.to_upper_camel_case();
2675
2676        let fields = record
2677            .fields
2678            .iter()
2679            .map(|field| {
2680                let ty = self.type_name(self.resolve, field.ty);
2681                let docs = format_docs(&field.docs);
2682                let field = field.name.to_upper_camel_case();
2683                format!("{docs}{field} {ty}")
2684            })
2685            .collect::<Vec<_>>()
2686            .join("\n");
2687
2688        let docs = format_docs(docs);
2689
2690        uwriteln!(
2691            self.src,
2692            "
2693{docs}type {name} struct {{
2694        {fields}
2695}}"
2696        )
2697    }
2698
2699    fn type_resource(&mut self, id: TypeId, name: &str, docs: &Docs) {
2700        self.generator.resources.insert(
2701            id,
2702            if self.in_import {
2703                Direction::Import
2704            } else {
2705                Direction::Export
2706            },
2707        );
2708
2709        let camel = name.to_upper_camel_case();
2710        let module = self
2711            .interface
2712            .map(|(_, key)| self.resolve.name_world_key(key))
2713            .unwrap_or_else(|| "$root".into());
2714
2715        if self.in_import {
2716            self.imports.insert(remote_pkg("runtime"));
2717            self.need_runtime = true;
2718            let docs = format_docs(docs);
2719            uwriteln!(
2720                self.src,
2721                r#"
2722//go:wasmimport {module} [resource-drop]{name}
2723func resourceDrop{camel}(handle int32)
2724
2725{docs}type {camel} struct {{
2726        handle *witRuntime.Handle
2727}}
2728
2729func (self *{camel}) TakeHandle() int32 {{
2730        return self.handle.Take()
2731}}
2732
2733func (self *{camel}) SetHandle(handle int32) {{
2734        self.handle.Set(handle)
2735}}
2736
2737func (self *{camel}) Handle() int32 {{
2738        return self.handle.Use()
2739}}
2740
2741func (self *{camel}) Drop() {{
2742	handle := self.handle.TakeOrNil()
2743	if handle != 0 {{
2744		resourceDrop{camel}(handle)
2745	}}
2746}}
2747
2748func {camel}FromOwnHandle(handleValue int32) *{camel} {{
2749        handle := witRuntime.MakeHandle(handleValue)
2750        value := &{camel}{{handle}}
2751        runtime.AddCleanup(value, func(_ int) {{
2752                handleValue := handle.TakeOrNil()
2753                if handleValue != 0 {{
2754                        resourceDrop{camel}(handleValue)
2755                }}
2756        }}, 0)
2757        return value
2758}}
2759
2760func {camel}FromBorrowHandle(handleValue int32) *{camel} {{
2761	handle := witRuntime.MakeHandle(handleValue)
2762	return &{camel}{{handle}}
2763}}
2764"#
2765            );
2766        } else {
2767            self.need_unsafe = true;
2768            uwriteln!(
2769                self.src,
2770                r#"
2771//go:wasmimport [export]{module} [resource-new]{name}
2772func resourceNew{camel}(pointer unsafe.Pointer) int32
2773
2774//go:wasmimport [export]{module} [resource-rep]{name}
2775func resourceRep{camel}(handle int32) unsafe.Pointer
2776
2777//go:wasmimport [export]{module} [resource-drop]{name}
2778func resourceDrop{camel}(handle int32)
2779
2780//go:wasmexport {module}#[dtor]{name}
2781func resourceDtor{camel}(rep int32) {{
2782        val := (*{camel})(unsafe.Pointer(uintptr(rep)))
2783        val.handle = 0
2784        val.pinner.Unpin()
2785        val.OnDrop()
2786}}
2787
2788func (self *{camel}) TakeHandle() int32 {{
2789	self.pinner.Pin(self)
2790	self.handle = resourceNew{camel}(unsafe.Pointer(self))
2791	return self.handle
2792}}
2793
2794func (self *{camel}) SetHandle(handle int32) {{
2795        if self.handle != handle {{
2796                panic("invalid handle")
2797        }}
2798}}
2799
2800func (self *{camel}) Drop() {{
2801	handle := self.handle
2802	if self.handle != 0 {{
2803		self.handle = 0
2804		resourceDrop{camel}(handle)
2805		self.pinner.Unpin()
2806                self.OnDrop()
2807	}}
2808}}
2809
2810func {camel}FromOwnHandle(handle int32) *{camel} {{
2811	return (*{camel})(unsafe.Pointer(resourceRep{camel}(handle)))
2812}}
2813
2814func {camel}FromBorrowHandle(rep int32) *{camel} {{
2815	return (*{camel})(unsafe.Pointer(uintptr(rep)))
2816}}
2817"#
2818            );
2819
2820            if self.generator.opts.generate_stubs {
2821                self.need_runtime = true;
2822                uwriteln!(
2823                    self.src,
2824                    r#"
2825type {camel} struct {{
2826        pinner runtime.Pinner
2827        handle int32
2828}}
2829
2830func (self *{camel}) OnDrop() {{}}
2831"#
2832                );
2833            }
2834        }
2835    }
2836
2837    fn type_flags(&mut self, _: TypeId, name: &str, flags: &Flags, docs: &Docs) {
2838        let repr = flags_repr(flags);
2839
2840        let name = name.to_upper_camel_case();
2841
2842        let constants = flags
2843            .flags
2844            .iter()
2845            .enumerate()
2846            .map(|(i, flag)| {
2847                let docs = format_docs(&flag.docs);
2848                let flag = flag.name.to_upper_camel_case();
2849                format!("{docs}{name}{flag} {repr} = 1 << {i}")
2850            })
2851            .collect::<Vec<_>>()
2852            .join("\n");
2853
2854        let docs = format_docs(docs);
2855
2856        uwriteln!(
2857            self.src,
2858            "
2859const (
2860{constants}
2861)
2862
2863{docs}type {name} = {repr}"
2864        )
2865    }
2866
2867    fn type_tuple(&mut self, _: TypeId, name: &str, tuple: &Tuple, docs: &Docs) {
2868        self.imports.insert(remote_pkg("types"));
2869        let count = tuple.types.len();
2870        self.generator.tuples.insert(count);
2871        let name = name.to_upper_camel_case();
2872        let docs = format_docs(docs);
2873        let types = tuple
2874            .types
2875            .iter()
2876            .map(|ty| self.type_name(self.resolve, *ty))
2877            .collect::<Vec<_>>()
2878            .join(", ");
2879
2880        uwriteln!(
2881            self.src,
2882            "{docs}type {name} = witTypes.Tuple{count}[{types}]"
2883        );
2884    }
2885
2886    fn type_variant(&mut self, _: TypeId, name: &str, variant: &Variant, docs: &Docs) {
2887        let repr = int_repr(variant.tag());
2888
2889        let name = name.to_upper_camel_case();
2890
2891        let constants = variant
2892            .cases
2893            .iter()
2894            .enumerate()
2895            .map(|(i, case)| {
2896                let docs = format_docs(&case.docs);
2897                let case = case.name.to_upper_camel_case();
2898                format!("{docs}{name}{case} {repr} = {i}")
2899            })
2900            .collect::<Vec<_>>()
2901            .join("\n");
2902
2903        let getters = variant
2904            .cases
2905            .iter()
2906            .filter_map(|case| {
2907                case.ty.map(|ty| {
2908                    let case = case.name.to_upper_camel_case();
2909                    let ty = self.type_name(self.resolve, ty);
2910                    format!(
2911                        r#"func (self {name}) {case}() {ty} {{
2912        if self.tag != {name}{case} {{
2913                panic("tag mismatch")
2914        }}
2915        return self.value.({ty})
2916}}
2917"#
2918                    )
2919                })
2920            })
2921            .collect::<Vec<_>>()
2922            .concat();
2923
2924        let constructors = variant
2925            .cases
2926            .iter()
2927            .map(|case| {
2928                let (param, value) = if let Some(ty) = case.ty {
2929                    let ty = self.type_name(self.resolve, ty);
2930                    (format!("value {ty}"), "value")
2931                } else {
2932                    (String::new(), "nil")
2933                };
2934                let case = case.name.to_upper_camel_case();
2935                format!(
2936                    r#"func Make{name}{case}({param}) {name} {{
2937        return {name}{{{name}{case}, {value}}}
2938}}
2939"#
2940                )
2941            })
2942            .collect::<Vec<_>>()
2943            .concat();
2944
2945        let docs = format_docs(docs);
2946
2947        uwriteln!(
2948            self.src,
2949            "
2950const (
2951{constants}
2952)
2953
2954{docs}type {name} struct {{
2955        tag {repr}
2956        value any
2957}}
2958
2959func (self {name}) Tag() {repr} {{
2960        return self.tag
2961}}
2962
2963{getters}
2964{constructors}
2965"
2966        )
2967    }
2968
2969    fn type_option(&mut self, _: TypeId, name: &str, payload: &Type, docs: &Docs) {
2970        self.generator.need_option = true;
2971        self.imports.insert(remote_pkg("types"));
2972        let name = name.to_upper_camel_case();
2973        let ty = self.type_name(self.resolve, *payload);
2974        let docs = format_docs(docs);
2975        uwriteln!(self.src, "{docs}type {name} = witTypes.Option[{ty}]");
2976    }
2977
2978    fn type_result(&mut self, _: TypeId, name: &str, result: &Result_, docs: &Docs) {
2979        self.generator.need_result = true;
2980        self.imports.insert(remote_pkg("types"));
2981        let name = name.to_upper_camel_case();
2982        let ok_type = result
2983            .ok
2984            .map(|ty| self.type_name(self.resolve, ty))
2985            .unwrap_or_else(|| {
2986                self.generator.need_unit = true;
2987                "witTypes.Unit".into()
2988            });
2989        let err_type = result
2990            .err
2991            .map(|ty| self.type_name(self.resolve, ty))
2992            .unwrap_or_else(|| {
2993                self.generator.need_unit = true;
2994                "witTypes.Unit".into()
2995            });
2996        let docs = format_docs(docs);
2997        uwriteln!(
2998            self.src,
2999            "{docs}type {name} = witTypes.Result[{ok_type}, {err_type}]"
3000        );
3001    }
3002
3003    fn type_enum(&mut self, _: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
3004        let repr = int_repr(enum_.tag());
3005
3006        let name = name.to_upper_camel_case();
3007
3008        let constants = enum_
3009            .cases
3010            .iter()
3011            .enumerate()
3012            .map(|(i, case)| {
3013                let docs = format_docs(&case.docs);
3014                let case = case.name.to_upper_camel_case();
3015                format!("{docs}{name}{case} {repr} = {i}")
3016            })
3017            .collect::<Vec<_>>()
3018            .join("\n");
3019
3020        let docs = format_docs(docs);
3021
3022        uwriteln!(
3023            self.src,
3024            "
3025const (
3026        {constants}
3027)
3028{docs}type {name} = {repr}"
3029        )
3030    }
3031
3032    fn type_alias(&mut self, _: TypeId, name: &str, ty: &Type, docs: &Docs) {
3033        let name = name.to_upper_camel_case();
3034        let ty = self.type_name(self.resolve, *ty);
3035        let docs = format_docs(docs);
3036        uwriteln!(self.src, "{docs}type {name} = {ty}");
3037    }
3038
3039    fn type_list(&mut self, _: TypeId, name: &str, ty: &Type, docs: &Docs) {
3040        let name = name.to_upper_camel_case();
3041        let ty = self.type_name(self.resolve, *ty);
3042        let docs = format_docs(docs);
3043        uwriteln!(self.src, "{docs}type {name} = []{ty}");
3044    }
3045
3046    fn type_fixed_length_list(&mut self, _: TypeId, name: &str, ty: &Type, size: u32, docs: &Docs) {
3047        let name = name.to_upper_camel_case();
3048        let ty = self.type_name(self.resolve, *ty);
3049        let docs = format_docs(docs);
3050        uwriteln!(self.src, "{docs}type {name} = [{size}]{ty}");
3051    }
3052
3053    fn type_map(&mut self, _id: TypeId, name: &str, key: &Type, value: &Type, docs: &Docs) {
3054        let name = name.to_upper_camel_case();
3055        let key = self.type_name(self.resolve, *key);
3056        let value = self.type_name(self.resolve, *value);
3057        let docs = format_docs(docs);
3058        uwriteln!(self.src, "{docs}type {name} = map[{key}]{value}");
3059    }
3060
3061    fn type_builtin(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs) {
3062        _ = (id, name, ty, docs);
3063        todo!()
3064    }
3065
3066    fn type_future(&mut self, id: TypeId, name: &str, _: &Option<Type>, docs: &Docs) {
3067        let name = name.to_upper_camel_case();
3068        let ty = self.type_name(self.resolve, Type::Id(id));
3069        let docs = format_docs(docs);
3070        uwriteln!(self.src, "{docs}type {name} = {ty}");
3071    }
3072
3073    fn type_stream(&mut self, id: TypeId, name: &str, _: &Option<Type>, docs: &Docs) {
3074        let name = name.to_upper_camel_case();
3075        let ty = self.type_name(self.resolve, Type::Id(id));
3076        let docs = format_docs(docs);
3077        uwriteln!(self.src, "{docs}type {name} = {ty}");
3078    }
3079}
3080
3081fn wasm_type(ty: WasmType) -> &'static str {
3082    match ty {
3083        WasmType::I32 => "int32",
3084        WasmType::I64 => "int64",
3085        WasmType::F32 => "float32",
3086        WasmType::F64 => "float64",
3087        WasmType::Pointer => "uintptr",
3088        WasmType::PointerOrI64 => "int64",
3089        WasmType::Length => "uint32",
3090    }
3091}
3092
3093fn format_docs(docs: &Docs) -> String {
3094    docs.contents
3095        .as_ref()
3096        .map(|v| {
3097            v.trim()
3098                .lines()
3099                .map(|line| format!("// {line}\n"))
3100                .collect::<Vec<_>>()
3101                .concat()
3102        })
3103        .unwrap_or_default()
3104}
3105
3106fn flags_repr(flags: &Flags) -> &'static str {
3107    match flags.repr() {
3108        FlagsRepr::U8 => "uint8",
3109        FlagsRepr::U16 => "uint16",
3110        FlagsRepr::U32(1) => "uint32",
3111        _ => unreachable!(),
3112    }
3113}
3114
3115fn int_repr(int: Int) -> &'static str {
3116    match int {
3117        Int::U8 => "uint8",
3118        Int::U16 => "uint16",
3119        Int::U32 => "uint32",
3120        Int::U64 => unreachable!(),
3121    }
3122}
3123
3124fn cast(op: &str, which: &Bitcast, need_math: &mut bool) -> String {
3125    match which {
3126        Bitcast::I32ToF32 | Bitcast::I64ToF32 => {
3127            *need_math = true;
3128            format!("math.Float32frombits(uint32({op}))")
3129        }
3130        Bitcast::F32ToI32 => {
3131            *need_math = true;
3132            format!("int32(math.Float32bits({op}))")
3133        }
3134        Bitcast::F32ToI64 => {
3135            *need_math = true;
3136            format!("int64(math.Float32bits({op}))")
3137        }
3138        Bitcast::I64ToF64 => {
3139            *need_math = true;
3140            format!("math.Float64frombits(uint64({op}))")
3141        }
3142        Bitcast::F64ToI64 => {
3143            *need_math = true;
3144            format!("int64(math.Float64bits({op}))")
3145        }
3146        Bitcast::I32ToI64 | Bitcast::LToI64 => {
3147            format!("int64({op})")
3148        }
3149        Bitcast::PToP64 => {
3150            format!("int64({op})")
3151        }
3152        Bitcast::I64ToI32 | Bitcast::I64ToL | Bitcast::PToI32 => {
3153            format!("int32({op})")
3154        }
3155        Bitcast::I64ToP64 | Bitcast::P64ToI64 => op.into(),
3156        Bitcast::P64ToP | Bitcast::LToP | Bitcast::I32ToP => {
3157            format!("uintptr({op})")
3158        }
3159        Bitcast::PToL => {
3160            format!("uint32({op})")
3161        }
3162        Bitcast::I32ToL => {
3163            format!("uint32({op})")
3164        }
3165        Bitcast::LToI32 => {
3166            format!("uint32({op})")
3167        }
3168        Bitcast::None => op.to_string(),
3169        Bitcast::Sequence(sequence) => {
3170            let [first, second] = &**sequence;
3171            let inner = cast(op, first, need_math);
3172            cast(&inner, second, need_math)
3173        }
3174    }
3175}
3176
3177fn any(resolve: &Resolve, ty: Type, fun: &dyn Fn(Type) -> bool) -> bool {
3178    if fun(ty) {
3179        return true;
3180    }
3181
3182    match ty {
3183        Type::Bool
3184        | Type::U8
3185        | Type::S8
3186        | Type::U16
3187        | Type::S16
3188        | Type::U32
3189        | Type::S32
3190        | Type::U64
3191        | Type::S64
3192        | Type::F32
3193        | Type::F64
3194        | Type::Char
3195        | Type::String => false,
3196        Type::Id(id) => {
3197            let ty = &resolve.types[id];
3198            match &ty.kind {
3199                TypeDefKind::Flags(_) | TypeDefKind::Enum(_) | TypeDefKind::Resource => false,
3200                TypeDefKind::Handle(Handle::Own(resource) | Handle::Borrow(resource)) => {
3201                    any(resolve, Type::Id(*resource), fun)
3202                }
3203                TypeDefKind::Record(record) => record
3204                    .fields
3205                    .iter()
3206                    .any(|field| any(resolve, field.ty, fun)),
3207                TypeDefKind::Variant(variant) => variant
3208                    .cases
3209                    .iter()
3210                    .any(|case| case.ty.map(|ty| any(resolve, ty, fun)).unwrap_or(false)),
3211                TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
3212                    any(resolve, *ty, fun)
3213                }
3214                TypeDefKind::Result(result) => result
3215                    .ok
3216                    .map(|ty| any(resolve, ty, fun))
3217                    .or_else(|| result.err.map(|ty| any(resolve, ty, fun)))
3218                    .unwrap_or(false),
3219                TypeDefKind::Tuple(tuple) => tuple.types.iter().any(|ty| any(resolve, *ty, fun)),
3220                TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => {
3221                    ty.map(|ty| any(resolve, ty, fun)).unwrap_or(false)
3222                }
3223                TypeDefKind::Map(key, value) => {
3224                    any(resolve, *key, fun) || any(resolve, *value, fun)
3225                }
3226                _ => todo!("{:?}", ty.kind),
3227            }
3228        }
3229        _ => todo!("{ty:?}"),
3230    }
3231}
3232
3233fn func_declaration(resolve: &Resolve, func: &Function) -> (String, bool) {
3234    match &func.kind {
3235        FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
3236            (func.item_name().to_upper_camel_case(), false)
3237        }
3238        FunctionKind::Constructor(ty) => {
3239            let ty = resolve.types[*ty]
3240                .name
3241                .as_ref()
3242                .unwrap()
3243                .to_upper_camel_case();
3244            (format!("Make{ty}"), false)
3245        }
3246        FunctionKind::Method(ty) | FunctionKind::AsyncMethod(ty) => {
3247            let ty = resolve.types[*ty]
3248                .name
3249                .as_ref()
3250                .unwrap()
3251                .to_upper_camel_case();
3252            let camel = func.item_name().to_upper_camel_case();
3253            (format!("(self *{ty}) {camel}"), true)
3254        }
3255        FunctionKind::Static(ty) | FunctionKind::AsyncStatic(ty) => {
3256            let ty = resolve.types[*ty]
3257                .name
3258                .as_ref()
3259                .unwrap()
3260                .to_upper_camel_case();
3261            let camel = func.item_name().to_upper_camel_case();
3262            (format!("{ty}{camel}"), false)
3263        }
3264    }
3265}
3266
3267fn maybe_gofmt<'a>(format: Format, code: &'a [u8]) -> Cow<'a, [u8]> {
3268    thread::scope(|s| {
3269        if let Format::True = format
3270            && let Ok((reader, mut writer)) = io::pipe()
3271        {
3272            s.spawn(move || {
3273                _ = writer.write_all(code);
3274            });
3275
3276            if let Ok(output) = Command::new("gofmt").stdin(reader).output()
3277                && output.status.success()
3278            {
3279                return Cow::Owned(output.stdout);
3280            }
3281        }
3282
3283        Cow::Borrowed(code)
3284    })
3285}