gofront 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +174 -403
  2. package/package.json +16 -19
  3. package/src/{codegen → backend/js}/expressions.js +265 -77
  4. package/src/{codegen → backend/js}/index.js +120 -89
  5. package/src/{codegen → backend/js}/runtime.js +102 -0
  6. package/src/{codegen → backend/js}/source-map.js +32 -0
  7. package/src/{codegen → backend/js}/statements.js +139 -64
  8. package/src/backend/js/stdlib/bits.js +32 -0
  9. package/src/{codegen → backend/js}/stdlib/errors.js +2 -2
  10. package/src/{codegen → backend/js}/stdlib/fmt.js +26 -8
  11. package/src/{codegen → backend/js}/stdlib/index.js +6 -0
  12. package/src/{codegen → backend/js}/stdlib/maps.js +1 -1
  13. package/src/{codegen → backend/js}/stdlib/path.js +2 -2
  14. package/src/backend/js/stdlib/shared.js +17 -0
  15. package/src/{codegen → backend/js}/stdlib/slices.js +1 -1
  16. package/src/{codegen → backend/js}/stdlib/sort.js +1 -1
  17. package/src/backend/js/stdlib/strconv.js +58 -0
  18. package/src/{codegen → backend/js}/stdlib/strings.js +4 -1
  19. package/src/{codegen → backend/js}/stdlib/testing.js +2 -2
  20. package/src/{codegen → backend/js}/stdlib/time.js +3 -3
  21. package/src/{codegen → backend/js}/templ.js +3 -3
  22. package/src/backend/wasm/boundary.js +1798 -0
  23. package/src/backend/wasm/emit-builtins.js +1103 -0
  24. package/src/backend/wasm/emit-exprs.js +1908 -0
  25. package/src/backend/wasm/emit-maps.js +1863 -0
  26. package/src/backend/wasm/emit-shared.js +519 -0
  27. package/src/backend/wasm/emit-stdlib.js +3006 -0
  28. package/src/backend/wasm/emit-stmts.js +2472 -0
  29. package/src/backend/wasm/emit.js +1376 -0
  30. package/src/backend/wasm/encode.js +937 -0
  31. package/src/backend/wasm/glue.js +144 -0
  32. package/src/backend/wasm/index.js +2790 -0
  33. package/src/backend/wasm/monomorph.js +711 -0
  34. package/src/backend/wasm/optimize.js +227 -0
  35. package/src/backend/wasm/types.js +544 -0
  36. package/src/backend/wasm/wat.js +302 -0
  37. package/src/cli-core.js +323 -75
  38. package/src/compiler.js +447 -14
  39. package/src/dev-server.js +56 -15
  40. package/src/index.js +99 -120
  41. package/src/lexer.js +18 -0
  42. package/src/lower/boxing.js +35 -0
  43. package/src/lower/captures.js +172 -0
  44. package/src/lower/embedding.js +30 -0
  45. package/src/lower/escape.js +164 -0
  46. package/src/lower/functions.js +302 -0
  47. package/src/lower/globals.js +316 -0
  48. package/src/lower/index.js +118 -0
  49. package/src/lower/ownership.js +137 -0
  50. package/src/lower/range.js +67 -0
  51. package/src/lower/walk.js +25 -0
  52. package/src/minifier.js +2 -0
  53. package/src/parser/index.js +8 -3
  54. package/src/resolver.js +3 -1
  55. package/src/test-runner.js +94 -20
  56. package/src/typechecker/assignability.js +42 -1
  57. package/src/typechecker/expressions.js +182 -3
  58. package/src/typechecker/index.js +261 -5
  59. package/src/typechecker/resolve.js +35 -6
  60. package/src/typechecker/stdlib/core.js +34 -19
  61. package/src/typechecker/stdlib/extended.js +18 -3
  62. package/src/typechecker/stdlib/shared.js +53 -0
  63. package/src/typechecker/stdlib.js +2 -0
  64. package/src/typechecker/types.js +259 -6
  65. package/src/vendor.js +2 -2
  66. package/src/codegen/stdlib/strconv.js +0 -33
  67. /package/src/{codegen → backend/js}/stdlib/builder.js +0 -0
  68. /package/src/{codegen → backend/js}/stdlib/bytes.js +0 -0
  69. /package/src/{codegen → backend/js}/stdlib/gom.js +0 -0
  70. /package/src/{codegen → backend/js}/stdlib/html.js +0 -0
  71. /package/src/{codegen → backend/js}/stdlib/io.js +0 -0
  72. /package/src/{codegen → backend/js}/stdlib/math.js +0 -0
  73. /package/src/{codegen → backend/js}/stdlib/os.js +0 -0
  74. /package/src/{codegen → backend/js}/stdlib/rand.js +0 -0
  75. /package/src/{codegen → backend/js}/stdlib/regexp.js +0 -0
  76. /package/src/{codegen → backend/js}/stdlib/unicode.js +0 -0
  77. /package/src/{codegen → backend/js}/stdlib/utf8.js +0 -0
@@ -0,0 +1,544 @@
1
+ // src/backend/wasm/types.js
2
+ // Maps GoFront types to WasmGC types and manages type registry.
3
+
4
+ import { SHARED_KINDS } from "../../typechecker/stdlib/shared.js";
5
+
6
+ // Name of the runtime's error struct (`errors.New`, `fmt.Errorf`, strconv).
7
+ export const ERROR_STRUCT = "__errorString";
8
+
9
+ // `*testing.T` is a JS-side object (the harness's __GoFront_T) passed through
10
+ // the boundary as an opaque externref.
11
+ export function isTestingT(goType) {
12
+ if (!goType) return false;
13
+ const base =
14
+ goType.kind === "pointer" || goType.kind === "PointerType"
15
+ ? goType.base
16
+ : goType.kind === "StarExpr"
17
+ ? (goType.expr ?? goType.operand)
18
+ : null;
19
+ return base?.name === "testing.T";
20
+ }
21
+
22
+ export function toWasmType(goType, checker = null, mod = null) {
23
+ if (!goType) return "i32";
24
+ if (typeof goType === "string") {
25
+ if (
26
+ goType === "i32" ||
27
+ goType === "i64" ||
28
+ goType === "f32" ||
29
+ goType === "f64" ||
30
+ goType === "anyref" ||
31
+ goType === "externref" ||
32
+ goType === "funcref"
33
+ ) {
34
+ return goType;
35
+ }
36
+ }
37
+ if (typeof goType === "object" && goType.kind === "ref") {
38
+ return goType;
39
+ }
40
+ if (isTestingT(goType)) return "externref";
41
+
42
+ // Pointer AST nodes
43
+ if (goType.kind === "PointerType") {
44
+ return toWasmType({ kind: "pointer", base: goType.base }, checker, mod);
45
+ }
46
+ if (goType.kind === "StarExpr") {
47
+ return toWasmType(
48
+ { kind: "pointer", base: goType.expr ?? goType.operand },
49
+ checker,
50
+ mod,
51
+ );
52
+ }
53
+
54
+ // Slice, Array, and Map AST nodes
55
+ if (goType.kind === "SliceType") {
56
+ return toWasmType({ kind: "slice", elem: goType.elem }, checker, mod);
57
+ }
58
+ if (goType.kind === "ArrayType") {
59
+ return toWasmType({ kind: "array", elem: goType.elem }, checker, mod);
60
+ }
61
+ if (goType.kind === "MapType") {
62
+ return toWasmType(
63
+ { kind: "map", key: goType.key, value: goType.value ?? goType.elem },
64
+ checker,
65
+ mod,
66
+ );
67
+ }
68
+
69
+ // TypeName AST node
70
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
71
+ if (mod?.getStructType(goType.name)) {
72
+ return {
73
+ kind: "ref",
74
+ nullable: true,
75
+ typeIndex: mod.getStructType(goType.name).typeIndex,
76
+ };
77
+ }
78
+ const resolved = checker?.types?.get(goType.name);
79
+ if (resolved) {
80
+ return toWasmType(resolved, checker, mod);
81
+ }
82
+ return toWasmType({ kind: "basic", name: goType.name }, checker, mod);
83
+ }
84
+
85
+ // Unwrap named types
86
+ if (goType.kind === "named") {
87
+ if (mod?.getStructType(goType.name)) {
88
+ return {
89
+ kind: "ref",
90
+ nullable: true,
91
+ typeIndex: mod.getStructType(goType.name).typeIndex,
92
+ };
93
+ }
94
+ if (goType.underlying) {
95
+ return toWasmType(goType.underlying, checker, mod);
96
+ }
97
+ }
98
+
99
+ // Untyped constants
100
+ if (goType.kind === "untyped") {
101
+ switch (goType.base) {
102
+ case "int":
103
+ return "i64"; // Default Go integer is int (i64 in WASM subset)
104
+ case "float64":
105
+ return "f64";
106
+ case "string":
107
+ return "externref";
108
+ case "bool":
109
+ return "i32";
110
+ default:
111
+ return "i64";
112
+ }
113
+ }
114
+
115
+ if (goType.kind === "basic") {
116
+ switch (goType.name) {
117
+ case "bool":
118
+ case "int8":
119
+ case "int16":
120
+ case "int32":
121
+ case "uint8":
122
+ case "uint16":
123
+ case "uint32":
124
+ case "byte":
125
+ case "rune":
126
+ return "i32";
127
+
128
+ case "int":
129
+ case "uint":
130
+ case "int64":
131
+ case "uint64":
132
+ case "uintptr":
133
+ return "i64";
134
+
135
+ case "float32":
136
+ return "f32";
137
+
138
+ case "float64":
139
+ return "f64";
140
+
141
+ case "string":
142
+ return "externref";
143
+
144
+ case "any":
145
+ return "anyref";
146
+
147
+ case "void":
148
+ return null;
149
+
150
+ default:
151
+ return "i64";
152
+ }
153
+ }
154
+
155
+ if (goType.kind === "pointer") {
156
+ // Struct pointer or boxed scalar
157
+ if (goType.base) {
158
+ const baseWType = toWasmType(goType.base, checker, mod);
159
+ if (
160
+ typeof baseWType === "object" &&
161
+ baseWType !== null &&
162
+ baseWType.kind === "ref"
163
+ ) {
164
+ return baseWType;
165
+ }
166
+ if (mod?.getBoxType) {
167
+ const box = mod.getBoxType(goType.base);
168
+ if (box)
169
+ return { kind: "ref", nullable: true, typeIndex: box.typeIndex };
170
+ }
171
+ }
172
+ return { kind: "ref", nullable: true, heapType: "any" };
173
+ }
174
+
175
+ if (goType.kind === "shared") {
176
+ if (mod?.getSharedType)
177
+ return {
178
+ kind: "ref",
179
+ nullable: true,
180
+ typeIndex: mod.getSharedType().typeIndex,
181
+ };
182
+ return { kind: "ref", nullable: true, heapType: "struct" };
183
+ }
184
+
185
+ if (goType.kind === "slice") {
186
+ if (mod?.getSliceType && goType.elem) {
187
+ const sliceInfo = mod.getSliceType(goType.elem);
188
+ return {
189
+ kind: "ref",
190
+ nullable: true,
191
+ typeIndex: sliceInfo.typeIndex,
192
+ };
193
+ }
194
+ return { kind: "ref", nullable: true, heapType: "struct" };
195
+ }
196
+
197
+ if (goType.kind === "array") {
198
+ if (mod?.getArrayType && goType.elem) {
199
+ const arrInfo = mod.getArrayType(goType.elem);
200
+ return {
201
+ kind: "ref",
202
+ nullable: true,
203
+ typeIndex: arrInfo.typeIndex,
204
+ };
205
+ }
206
+ return { kind: "ref", nullable: true, heapType: "array" };
207
+ }
208
+
209
+ if (goType.kind === "map") {
210
+ const key = goType.key;
211
+ const val = goType.value ?? goType.elem;
212
+ if (mod?.getMapType && key && val) {
213
+ const mapInfo = mod.getMapType(key, val);
214
+ return {
215
+ kind: "ref",
216
+ nullable: true,
217
+ typeIndex: mapInfo.typeIndex,
218
+ };
219
+ }
220
+ return { kind: "ref", nullable: true, heapType: "struct" };
221
+ }
222
+
223
+ if (goType.kind === "struct") {
224
+ if (goType.name && mod?.getStructType(goType.name)) {
225
+ return {
226
+ kind: "ref",
227
+ nullable: true,
228
+ typeIndex: mod.getStructType(goType.name).typeIndex,
229
+ };
230
+ }
231
+ return { kind: "ref", nullable: true, heapType: "struct" };
232
+ }
233
+
234
+ if (isFuncType(goType, checker)) {
235
+ if (mod) {
236
+ const closureInfo = mod.getClosureType(goType);
237
+ return {
238
+ kind: "ref",
239
+ nullable: true,
240
+ typeIndex: closureInfo.typeIndex,
241
+ };
242
+ }
243
+ return "funcref";
244
+ }
245
+
246
+ if (goType.kind === "interface" || goType.kind === "InterfaceType") {
247
+ return "anyref";
248
+ }
249
+
250
+ return "i32";
251
+ }
252
+
253
+ export function isStructType(goType, checker = null, mod = null) {
254
+ if (!goType) return false;
255
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
256
+ if (mod?.getStructType?.(goType.name)) return true;
257
+ const resolved = checker?.types?.get(goType.name);
258
+ if (resolved) return isStructType(resolved, checker, mod);
259
+ }
260
+ if (goType.kind === "named") {
261
+ if (mod?.getStructType?.(goType.name)) return true;
262
+ if (goType.underlying) return isStructType(goType.underlying, checker, mod);
263
+ }
264
+ return goType.kind === "struct" || goType.kind === "StructType";
265
+ }
266
+
267
+ export function isPointerToStruct(goType, checker = null, mod = null) {
268
+ if (!goType) return false;
269
+ if (goType.kind === "PointerType" || goType.kind === "pointer") {
270
+ return isStructType(goType.base, checker, mod);
271
+ }
272
+ if (goType.kind === "StarExpr") {
273
+ return isStructType(goType.expr ?? goType.operand, checker, mod);
274
+ }
275
+ return false;
276
+ }
277
+
278
+ export function isSliceType(goType, checker = null) {
279
+ if (!goType) return false;
280
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
281
+ const resolved = checker?.types?.get(goType.name);
282
+ if (resolved) return isSliceType(resolved, checker);
283
+ }
284
+ if (goType.kind === "named" && goType.underlying) {
285
+ return isSliceType(goType.underlying, checker);
286
+ }
287
+ return goType.kind === "slice" || goType.kind === "SliceType";
288
+ }
289
+
290
+ // `gofront/shared` linear-memory buffer: returns the SHARED_KINDS entry
291
+ // (elem, ctor, bytes, key) or null.
292
+ export function getSharedInfo(goType, checker = null) {
293
+ if (!goType) return null;
294
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
295
+ const resolved = checker?.types?.get(goType.name);
296
+ return resolved ? getSharedInfo(resolved, checker) : null;
297
+ }
298
+ if (goType.kind === "named" && goType.underlying)
299
+ return getSharedInfo(goType.underlying, checker);
300
+ if (goType.kind !== "shared") return null;
301
+ return { name: goType.shared, ...SHARED_KINDS[goType.shared] };
302
+ }
303
+
304
+ export function isArrayType(goType, checker = null) {
305
+ if (!goType) return false;
306
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
307
+ const resolved = checker?.types?.get(goType.name);
308
+ if (resolved) return isArrayType(resolved, checker);
309
+ }
310
+ if (goType.kind === "named" && goType.underlying) {
311
+ return isArrayType(goType.underlying, checker);
312
+ }
313
+ return goType.kind === "array" || goType.kind === "ArrayType";
314
+ }
315
+
316
+ export function isMapType(goType, checker = null) {
317
+ if (!goType) return false;
318
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
319
+ const resolved = checker?.types?.get(goType.name);
320
+ if (resolved) return isMapType(resolved, checker);
321
+ }
322
+ if (goType.kind === "named" && goType.underlying) {
323
+ return isMapType(goType.underlying, checker);
324
+ }
325
+ return goType.kind === "map" || goType.kind === "MapType";
326
+ }
327
+
328
+ // Returns `{ keyType, valType }` (Go types) for a map type, or nulls.
329
+ export function getMapKeyValTypes(goType, checker = null) {
330
+ if (!goType) return { keyType: null, valType: null };
331
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
332
+ const resolved = checker?.types?.get(goType.name);
333
+ if (resolved) return getMapKeyValTypes(resolved, checker);
334
+ }
335
+ if (goType.kind === "named" && goType.underlying) {
336
+ return getMapKeyValTypes(goType.underlying, checker);
337
+ }
338
+ if (goType.kind === "map" || goType.kind === "MapType") {
339
+ const key = goType.key ?? goType.keyType;
340
+ const val =
341
+ goType.value ?? goType.elem ?? goType.valueType ?? goType.valType;
342
+ return { keyType: key, valType: val };
343
+ }
344
+ return { keyType: null, valType: null };
345
+ }
346
+
347
+ export function isStringType(goType, checker = null) {
348
+ if (!goType) return false;
349
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
350
+ const resolved = checker?.types?.get(goType.name);
351
+ if (resolved) return isStringType(resolved, checker);
352
+ return goType.name === "string";
353
+ }
354
+ if (goType.kind === "named") {
355
+ if (goType.name === "string") return true;
356
+ if (goType.underlying) return isStringType(goType.underlying, checker);
357
+ }
358
+ if (goType.kind === "basic") return goType.name === "string";
359
+ if (goType.kind === "untyped") return goType.base === "string";
360
+ return false;
361
+ }
362
+
363
+ export function isAnyType(goType, checker = null) {
364
+ if (!goType) return false;
365
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
366
+ const resolved = checker?.types?.get(goType.name);
367
+ if (resolved) return isAnyType(resolved, checker);
368
+ return goType.name === "any" || goType.name === "interface{}";
369
+ }
370
+ if (goType.kind === "named") {
371
+ if (goType.name === "any" || goType.name === "interface{}") return true;
372
+ if (goType.underlying) return isAnyType(goType.underlying, checker);
373
+ }
374
+ if (goType.kind === "basic") return goType.name === "any";
375
+ if (goType.kind === "interface") return true;
376
+ return false;
377
+ }
378
+
379
+ export function isInterfaceType(goType, checker = null) {
380
+ if (!goType) return false;
381
+ if (goType.kind === "interface" || goType.kind === "InterfaceType")
382
+ return true;
383
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
384
+ if (goType.name === "any" || goType.name === "interface{}") return true;
385
+ const resolved = checker?.types?.get(goType.name);
386
+ if (resolved) return isInterfaceType(resolved, checker);
387
+ }
388
+ if (goType.kind === "named") {
389
+ if (goType.name === "any" || goType.name === "interface{}") return true;
390
+ if (goType.underlying) return isInterfaceType(goType.underlying, checker);
391
+ const resolved = checker?.types?.get(goType.name);
392
+ if (resolved) return isInterfaceType(resolved, checker);
393
+ }
394
+ return false;
395
+ }
396
+
397
+ // The built-in `error` interface (checker ERROR type or its name).
398
+ export function isErrorType(goType) {
399
+ if (!goType) return false;
400
+ if (goType.kind === "interface") return goType.name === "error";
401
+ if (
402
+ (goType.kind === "named" ||
403
+ goType.kind === "TypeName" ||
404
+ goType.kind === "Ident") &&
405
+ goType.name === "error"
406
+ ) {
407
+ return true;
408
+ }
409
+ if (goType.kind === "named" && goType.underlying)
410
+ return isErrorType(goType.underlying);
411
+ return false;
412
+ }
413
+
414
+ export function isNonEmptyInterface(goType, checker = null) {
415
+ if (!goType) return false;
416
+ if (goType.name === "any" || goType.name === "interface{}") return false;
417
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
418
+ const resolved = checker?.types?.get(goType.name);
419
+ if (resolved) return isNonEmptyInterface(resolved, checker);
420
+ }
421
+ if (goType.kind === "named") {
422
+ if (goType.name === "any" || goType.name === "interface{}") return false;
423
+ if (goType.underlying)
424
+ return isNonEmptyInterface(goType.underlying, checker);
425
+ const resolved = checker?.types?.get(goType.name);
426
+ if (resolved) return isNonEmptyInterface(resolved, checker);
427
+ }
428
+ if (goType.kind === "interface" || goType.kind === "InterfaceType") {
429
+ if (goType.methods instanceof Map) return goType.methods.size > 0;
430
+ if (Array.isArray(goType.methods)) return goType.methods.length > 0;
431
+ if (goType.methods instanceof Set) return goType.methods.size > 0;
432
+ return false;
433
+ }
434
+ return false;
435
+ }
436
+
437
+ export function getReceiverTypeName(recvType, _node = null) {
438
+ if (recvType) {
439
+ let t = recvType;
440
+ while (t.kind === "pointer") t = t.base;
441
+ if (t.name) return t.name;
442
+ if (t.kind === "named") return t.name;
443
+ if (t.kind === "TypeName" || t.kind === "Ident") return t.name;
444
+ }
445
+ return null;
446
+ }
447
+
448
+ export function isSigned(goType) {
449
+ if (!goType) return true;
450
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
451
+ return isSigned({ kind: "basic", name: goType.name });
452
+ }
453
+ if (goType.kind === "named" && goType.underlying) {
454
+ return isSigned(goType.underlying);
455
+ }
456
+ if (goType.kind === "basic") {
457
+ return !goType.name.startsWith("uint") && goType.name !== "byte";
458
+ }
459
+ return true;
460
+ }
461
+
462
+ export function isFloat(goType) {
463
+ if (!goType) return false;
464
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
465
+ return isFloat({ kind: "basic", name: goType.name });
466
+ }
467
+ if (goType.kind === "named" && goType.underlying) {
468
+ return isFloat(goType.underlying);
469
+ }
470
+ if (goType.kind === "untyped") return goType.base === "float64";
471
+ return (
472
+ goType.kind === "basic" &&
473
+ (goType.name === "float32" || goType.name === "float64")
474
+ );
475
+ }
476
+
477
+ export function isFuncType(goType, checker = null) {
478
+ if (!goType) return false;
479
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
480
+ const resolved = checker?.types?.get(goType.name);
481
+ if (resolved) return isFuncType(resolved, checker);
482
+ }
483
+ if (goType.kind === "named" && goType.underlying) {
484
+ return isFuncType(goType.underlying, checker);
485
+ }
486
+ return (
487
+ goType.kind === "func" ||
488
+ goType.kind === "FuncType" ||
489
+ goType.kind === "FuncLit" ||
490
+ goType.kind === "FuncDecl"
491
+ );
492
+ }
493
+
494
+ export function getFuncSignature(goType, checker = null) {
495
+ if (!goType) return { params: [], returns: [] };
496
+ if (goType.kind === "TypeName" || goType.kind === "Ident") {
497
+ const resolved = checker?.types?.get(goType.name);
498
+ if (resolved) return getFuncSignature(resolved, checker);
499
+ }
500
+ if (goType.kind === "named" && goType.underlying) {
501
+ return getFuncSignature(goType.underlying, checker);
502
+ }
503
+ if (
504
+ goType.kind === "FuncType" ||
505
+ goType.kind === "FuncLit" ||
506
+ goType.kind === "FuncDecl"
507
+ ) {
508
+ const params = (goType.params ?? []).map((p) => p.type ?? p);
509
+ const returns = [];
510
+ if (goType.returnType) {
511
+ if (
512
+ goType.returnType.kind === "TupleType" ||
513
+ goType.returnType.kind === "tuple"
514
+ ) {
515
+ returns.push(...(goType.returnType.types ?? []));
516
+ } else {
517
+ returns.push(goType.returnType);
518
+ }
519
+ } else if (goType.returns) {
520
+ for (const r of goType.returns) {
521
+ if ((r?.kind === "tuple" || r?.kind === "TupleType") && r.types) {
522
+ returns.push(...r.types);
523
+ } else {
524
+ returns.push(r);
525
+ }
526
+ }
527
+ }
528
+ return { params, returns };
529
+ }
530
+ if (goType.kind === "func") {
531
+ const rawReturns =
532
+ goType.returns ?? (goType.returnType ? [goType.returnType] : []);
533
+ const returns = [];
534
+ for (const r of rawReturns) {
535
+ if ((r?.kind === "tuple" || r?.kind === "TupleType") && r.types) {
536
+ returns.push(...r.types);
537
+ } else {
538
+ returns.push(r);
539
+ }
540
+ }
541
+ return { params: goType.params ?? [], returns };
542
+ }
543
+ return { params: [], returns: [] };
544
+ }