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