gofront 1.7.0 → 1.9.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 (194) hide show
  1. package/README.md +14 -14
  2. package/package.json +10 -38
  3. package/src/backend/js/expressions.js +2060 -389
  4. package/src/backend/js/index.js +586 -174
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +936 -1644
  7. package/src/backend/js/statements.js +1349 -132
  8. package/src/backend/js/stdlib/index.js +51 -94
  9. package/src/backend/js/templ.js +67 -118
  10. package/src/backend/js/type-info.js +436 -0
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +80 -0
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +753 -872
  15. package/src/backend/wasm/emit-builtins.js +914 -237
  16. package/src/backend/wasm/emit-exprs.js +1456 -195
  17. package/src/backend/wasm/emit-maps.js +78 -380
  18. package/src/backend/wasm/emit-stmts.js +1659 -214
  19. package/src/backend/wasm/emit.js +614 -88
  20. package/src/backend/wasm/encode.js +43 -13
  21. package/src/backend/wasm/globals.js +491 -0
  22. package/src/backend/wasm/glue.js +2 -4
  23. package/src/backend/wasm/index.js +406 -3195
  24. package/src/backend/wasm/method-expr.js +392 -0
  25. package/src/backend/wasm/module-emitter.js +1615 -0
  26. package/src/backend/wasm/monomorph.js +164 -9
  27. package/src/backend/wasm/natives.js +596 -0
  28. package/src/backend/wasm/prescan.js +249 -0
  29. package/src/backend/wasm/prune-funcs.js +89 -0
  30. package/src/backend/wasm/stdlib/index.js +2 -37
  31. package/src/backend/wasm/stdlib/simd.js +293 -28
  32. package/src/backend/wasm/types.js +260 -27
  33. package/src/backend/wasm/variadic.js +93 -0
  34. package/src/backend/wasm/wat.js +47 -20
  35. package/src/{cli-core.js → cli/cli-core.js} +241 -11
  36. package/src/{test-runner.js → cli/test-runner.js} +188 -122
  37. package/src/{vendor.js → cli/vendor.js} +3 -4
  38. package/src/compiler.js +202 -386
  39. package/src/index.js +15 -169
  40. package/src/{lexer.js → lexer/lexer.js} +203 -62
  41. package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
  42. package/src/{tokens.js → lexer/tokens.js} +2 -0
  43. package/src/link/sourcemap.js +97 -0
  44. package/src/link/stdlib.js +737 -0
  45. package/src/link/type-names.js +148 -0
  46. package/src/link/wasm.js +318 -0
  47. package/src/lower/bounds.js +547 -0
  48. package/src/lower/boxing.js +1 -1
  49. package/src/lower/captures.js +267 -64
  50. package/src/lower/embedding.js +32 -3
  51. package/src/lower/errors-as.js +196 -0
  52. package/src/lower/fmt-formatters.js +905 -0
  53. package/src/lower/functions.js +2 -0
  54. package/src/lower/gen-types.js +274 -0
  55. package/src/lower/index.js +33 -19
  56. package/src/lower/json-codecs.js +1379 -0
  57. package/src/lower/ownership.js +47 -8
  58. package/src/lower/range.js +86 -1
  59. package/src/lower/reachability.js +150 -0
  60. package/src/lower/walk.js +12 -0
  61. package/src/parser/declarations.js +83 -15
  62. package/src/parser/expressions.js +110 -18
  63. package/src/parser/index.js +2 -1
  64. package/src/parser/statements.js +38 -22
  65. package/src/{templ-parser.js → parser/templ.js} +179 -17
  66. package/src/parser/types.js +70 -9
  67. package/src/resolver.js +21 -1
  68. package/src/typechecker/assignability.js +291 -19
  69. package/src/typechecker/const-fold.js +399 -0
  70. package/src/typechecker/constants.js +282 -0
  71. package/src/typechecker/expressions.js +1220 -183
  72. package/src/typechecker/index.js +659 -92
  73. package/src/typechecker/init-order.js +426 -0
  74. package/src/typechecker/operand-text.js +40 -0
  75. package/src/typechecker/resolve.js +613 -62
  76. package/src/typechecker/statements.js +212 -20
  77. package/src/typechecker/stdlib/excluded.js +902 -0
  78. package/src/typechecker/stdlib/index.js +38 -0
  79. package/src/typechecker/stdlib/simd.js +65 -15
  80. package/src/typechecker/termination.js +11 -2
  81. package/src/typechecker/types.js +268 -514
  82. package/stdlib/bytes/buffer.go +479 -0
  83. package/stdlib/bytes/bytes.go +1010 -0
  84. package/stdlib/bytes/reader.go +161 -0
  85. package/stdlib/cmp/cmp.go +65 -0
  86. package/stdlib/context/context.go +115 -0
  87. package/stdlib/crypto/rand/rand.go +34 -0
  88. package/stdlib/crypto/sha256/sha256.go +249 -0
  89. package/stdlib/encoding/base64/base64.go +331 -0
  90. package/stdlib/encoding/binary/binary.go +332 -0
  91. package/stdlib/encoding/hex/hex.go +140 -0
  92. package/stdlib/encoding/json/errors.go +31 -0
  93. package/stdlib/encoding/json/indent.go +71 -0
  94. package/stdlib/encoding/json/json.go +62 -0
  95. package/stdlib/encoding/json/number.go +12 -0
  96. package/stdlib/encoding/json/stream.go +173 -0
  97. package/stdlib/errors/errors.go +174 -0
  98. package/stdlib/fmt/errors.go +110 -0
  99. package/stdlib/fmt/format.go +732 -0
  100. package/stdlib/fmt/print.go +1232 -0
  101. package/stdlib/gom/gom.go +293 -0
  102. package/stdlib/hash/hash.go +53 -0
  103. package/stdlib/html/html.go +251 -0
  104. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  105. package/stdlib/internal/jsonrt/dec.go +871 -0
  106. package/stdlib/internal/jsonrt/enc.go +516 -0
  107. package/stdlib/internal/jsonrt/indent.go +135 -0
  108. package/stdlib/internal/jsonrt/number.go +27 -0
  109. package/stdlib/internal/jsonrt/reader.go +73 -0
  110. package/stdlib/internal/jsonrt/scanner.go +658 -0
  111. package/stdlib/io/io.go +502 -0
  112. package/stdlib/iter/iter.go +18 -0
  113. package/stdlib/maps/maps.go +131 -0
  114. package/stdlib/math/bits/bits.go +507 -0
  115. package/stdlib/math/extra.go +272 -0
  116. package/stdlib/math/math.go +439 -0
  117. package/stdlib/math/rand/rand.go +297 -0
  118. package/stdlib/os/os.go +93 -0
  119. package/stdlib/path/filepath/filepath.go +47 -0
  120. package/stdlib/path/path.go +394 -0
  121. package/stdlib/regexp/regexp.go +231 -0
  122. package/stdlib/slices/slices.go +526 -0
  123. package/stdlib/slices/sort.go +209 -0
  124. package/stdlib/slices/zsort_cmp.go +480 -0
  125. package/stdlib/slices/zsort_ordered.go +482 -0
  126. package/stdlib/sort/sort.go +500 -0
  127. package/stdlib/sort/zsort_func.go +480 -0
  128. package/stdlib/sort/zsort_iface.go +480 -0
  129. package/stdlib/strconv/float.go +1699 -0
  130. package/stdlib/strconv/isprint.go +752 -0
  131. package/stdlib/strconv/quote.go +526 -0
  132. package/stdlib/strconv/strconv.go +616 -0
  133. package/stdlib/strings/builder.go +95 -0
  134. package/stdlib/strings/reader.go +163 -0
  135. package/stdlib/strings/replacer.go +102 -0
  136. package/stdlib/strings/strings.go +807 -0
  137. package/stdlib/sync/sync.go +268 -0
  138. package/stdlib/testing/async_js.go +61 -0
  139. package/stdlib/testing/benchmark.go +297 -0
  140. package/stdlib/testing/testing.go +523 -0
  141. package/stdlib/time/duration.go +233 -0
  142. package/stdlib/time/format.go +745 -0
  143. package/stdlib/time/parse.go +790 -0
  144. package/stdlib/time/sleep_js.go +63 -0
  145. package/stdlib/time/time.go +834 -0
  146. package/stdlib/unicode/unicode.go +250 -0
  147. package/stdlib/unicode/utf8/utf8.go +464 -0
  148. package/src/backend/js/stdlib/base64.js +0 -12
  149. package/src/backend/js/stdlib/binary.js +0 -102
  150. package/src/backend/js/stdlib/bits.js +0 -46
  151. package/src/backend/js/stdlib/builder.js +0 -63
  152. package/src/backend/js/stdlib/bytes.js +0 -122
  153. package/src/backend/js/stdlib/errors.js +0 -44
  154. package/src/backend/js/stdlib/fmt.js +0 -178
  155. package/src/backend/js/stdlib/gom.js +0 -155
  156. package/src/backend/js/stdlib/hex.js +0 -17
  157. package/src/backend/js/stdlib/html.js +0 -20
  158. package/src/backend/js/stdlib/io.js +0 -137
  159. package/src/backend/js/stdlib/json.js +0 -972
  160. package/src/backend/js/stdlib/maps.js +0 -45
  161. package/src/backend/js/stdlib/math.js +0 -69
  162. package/src/backend/js/stdlib/os.js +0 -13
  163. package/src/backend/js/stdlib/path.js +0 -48
  164. package/src/backend/js/stdlib/rand.js +0 -32
  165. package/src/backend/js/stdlib/regexp.js +0 -54
  166. package/src/backend/js/stdlib/sha256.js +0 -12
  167. package/src/backend/js/stdlib/shared.js +0 -17
  168. package/src/backend/js/stdlib/simd.js +0 -24
  169. package/src/backend/js/stdlib/slices.js +0 -77
  170. package/src/backend/js/stdlib/sort.js +0 -30
  171. package/src/backend/js/stdlib/strconv.js +0 -74
  172. package/src/backend/js/stdlib/strings.js +0 -222
  173. package/src/backend/js/stdlib/sync.js +0 -13
  174. package/src/backend/js/stdlib/testing.js +0 -34
  175. package/src/backend/js/stdlib/time.js +0 -128
  176. package/src/backend/js/stdlib/unicode.js +0 -25
  177. package/src/backend/js/stdlib/utf8.js +0 -26
  178. package/src/backend/wasm/const-fold.js +0 -205
  179. package/src/backend/wasm/emit-stdlib.js +0 -13
  180. package/src/backend/wasm/stdlib/bytes.js +0 -5039
  181. package/src/backend/wasm/stdlib/core.js +0 -8903
  182. package/src/backend/wasm/stdlib/io.js +0 -2161
  183. package/src/backend/wasm/stdlib/packages.js +0 -2400
  184. package/src/backend/wasm/stdlib/pure.js +0 -720
  185. package/src/backend/wasm/stdlib/time.js +0 -1200
  186. package/src/typechecker/stdlib/core.js +0 -801
  187. package/src/typechecker/stdlib/extended.js +0 -914
  188. package/src/typechecker/stdlib.js +0 -22
  189. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  190. /package/src/{colors.js → cli/colors.js} +0 -0
  191. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  192. /package/src/{minifier.js → cli/minifier.js} +0 -0
  193. /package/src/{project-config.js → cli/project-config.js} +0 -0
  194. /package/src/{pwa.js → cli/pwa.js} +0 -0
@@ -7,6 +7,7 @@
7
7
  // (e.g. Identity$int, Box$int, Stack$int.Push) and re-typechecks the monomorphised AST.
8
8
 
9
9
  import { TypeChecker } from "../../typechecker/index.js";
10
+ import { goTypeName } from "../shared/fmt-types.js";
10
11
 
11
12
  /**
12
13
  * Returns true if the AST contains any generic declarations.
@@ -33,7 +34,13 @@ export function hasGenerics(programs) {
33
34
  /**
34
35
  * Returns a stable identifier-safe string key for any Go type or AST type node.
35
36
  */
37
+ // A qualified type argument (`time.Duration`) becomes part of a JS and wasm
38
+ // export identifier, so its dot is replaced.
36
39
  function typeKey(t) {
40
+ return rawTypeKey(t).replaceAll(".", "_");
41
+ }
42
+
43
+ function rawTypeKey(t) {
37
44
  if (!t) return "any";
38
45
  if (typeof t === "string") return t;
39
46
  if (t.kind === "basic") return t.name;
@@ -78,7 +85,7 @@ function typeKey(t) {
78
85
  /**
79
86
  * Converts a Go type representation or AST type node into a concrete AST type node.
80
87
  */
81
- function typeToTypeNode(t) {
88
+ export function typeToTypeNode(t) {
82
89
  if (!t) return { kind: "TypeName", name: "any" };
83
90
  if (typeof t === "string") return { kind: "TypeName", name: t };
84
91
  if (
@@ -112,7 +119,11 @@ function typeToTypeNode(t) {
112
119
  if (t.kind === "array") {
113
120
  return {
114
121
  kind: "ArrayType",
115
- len: t.len ?? t.size ?? 0,
122
+ size: {
123
+ kind: "BasicLit",
124
+ litKind: "INT",
125
+ value: String(t.len ?? t.size ?? 0),
126
+ },
116
127
  elem: typeToTypeNode(t.elem),
117
128
  };
118
129
  }
@@ -127,22 +138,92 @@ function typeToTypeNode(t) {
127
138
  return { kind: "TypeName", name: t.name ?? "any" };
128
139
  }
129
140
 
141
+ // Replaces the type parameters inside a checker type (`[]E`, `map[K]V`,
142
+ // `Box[E]`) by their type arguments; the result mixes checker types and the
143
+ // AST type nodes of the substitution, which `typeKey` and `typeToTypeNode`
144
+ // both accept.
145
+ function substituteInType(t, map) {
146
+ if (!t || typeof t !== "object") return t;
147
+ const sub = (x) => substituteInType(x, map);
148
+ switch (t.kind) {
149
+ case "typeParam":
150
+ return map.has(t.name) ? map.get(t.name) : t;
151
+ case "slice":
152
+ case "array":
153
+ return { ...t, elem: sub(t.elem) };
154
+ case "pointer":
155
+ return { ...t, base: sub(t.base) };
156
+ case "map":
157
+ return { ...t, key: sub(t.key), value: sub(t.value) };
158
+ case "func":
159
+ return {
160
+ ...t,
161
+ params: (t.params ?? []).map(sub),
162
+ returns: (t.returns ?? []).map(sub),
163
+ };
164
+ case "named":
165
+ return t.typeArgs?.length ? { ...t, typeArgs: t.typeArgs.map(sub) } : t;
166
+ default:
167
+ return t;
168
+ }
169
+ }
170
+
171
+ // A partial instantiation (`Grow[S](nil, n)`) lists only the explicit type
172
+ // arguments; the checker recorded the complete list, which replaces it.
173
+ function completeTypeArgs(node, typeSubstMap) {
174
+ if (node._typeArgs?.length > (node.typeArgs?.length ?? 0))
175
+ return node._typeArgs.map((t) => substituteInType(t, typeSubstMap));
176
+ return node.typeArgs;
177
+ }
178
+
130
179
  function getSpecializedName(baseName, typeArgs) {
131
180
  if (!typeArgs || typeArgs.length === 0) return baseName;
132
181
  const keys = typeArgs.map(typeKey).join("$");
133
182
  return `${baseName}$${keys}`;
134
183
  }
135
184
 
185
+ const KEPT_CLONE_KEYS = new Set(["_typeArgs", "_line", "_col", "_spread"]);
186
+
136
187
  function cloneAst(node) {
137
188
  if (!node || typeof node !== "object") return node;
138
189
  if (Array.isArray(node)) return node.map(cloneAst);
139
190
  const copy = {};
140
191
  for (const [k, v] of Object.entries(node)) {
192
+ // Side tables are dropped, except source positions (for diagnostics in
193
+ // the specialised body) and the inferred type arguments of a generic
194
+ // call inside a generic body: substitution needs them to specialise the
195
+ // callee (`isNaN(x)` inside `Compare[T]`).
196
+ if (k.startsWith("_") && !KEPT_CLONE_KEYS.has(k)) continue;
141
197
  copy[k] = cloneAst(v);
142
198
  }
199
+ // Named results hang off the return type node and alias its types; keep
200
+ // just the names so `rebindNamedResults` can rebuild them after the types
201
+ // are substituted.
202
+ const named = node.returnType?._namedReturns;
203
+ if (named) copy._resultNames = named.map((r) => r.name);
143
204
  return copy;
144
205
  }
145
206
 
207
+ // Re-attaches named results (`(old *T)`) to every function in a cloned and
208
+ // substituted tree, pointing at the substituted type nodes.
209
+ function rebindNamedResults(node) {
210
+ if (!node || typeof node !== "object") return;
211
+ if (Array.isArray(node)) {
212
+ for (const n of node) rebindNamedResults(n);
213
+ return;
214
+ }
215
+ if (node._resultNames && node.returnType) {
216
+ const rt = node.returnType;
217
+ rt._namedReturns = node._resultNames.map((name, i) => ({
218
+ name,
219
+ type: rt.kind === "TupleType" ? rt.types[i] : rt,
220
+ }));
221
+ }
222
+ for (const [k, v] of Object.entries(node)) {
223
+ if (!k.startsWith("_")) rebindNamedResults(v);
224
+ }
225
+ }
226
+
146
227
  /**
147
228
  * Replaces references to type parameters in AST nodes with concrete types.
148
229
  */
@@ -214,6 +295,7 @@ function substituteTypesInAst(
214
295
  }
215
296
  const baseName = node.expr?.name;
216
297
  if (baseName) {
298
+ node.typeArgs = completeTypeArgs(node, typeSubstMap);
217
299
  const sName = getSpecializedName(baseName, node.typeArgs);
218
300
  const isType = genericTypes ? genericTypes.has(baseName) : false;
219
301
  if (onGenericUsage) {
@@ -233,6 +315,13 @@ function substituteTypesInAst(
233
315
  // 3b. CompositeLit
234
316
  if (node.kind === "CompositeLit") {
235
317
  const targetProp = node.typeExpr ? "typeExpr" : node.type ? "type" : null;
318
+ // `S{a, b}` with S a type parameter: the type is a bare identifier.
319
+ if (
320
+ targetProp &&
321
+ node[targetProp]?.kind === "Ident" &&
322
+ typeSubstMap.has(node[targetProp].name)
323
+ )
324
+ node[targetProp] = cloneAst(typeSubstMap.get(node[targetProp].name));
236
325
  if (targetProp && node[targetProp]) {
237
326
  node[targetProp] = substituteTypesInAst(
238
327
  node[targetProp],
@@ -246,6 +335,35 @@ function substituteTypesInAst(
246
335
 
247
336
  // 4. CallExpr
248
337
  if (node.kind === "CallExpr") {
338
+ // `T(x)` with T a type parameter becomes the conversion `int8(x)`.
339
+ const conv =
340
+ node.func?.kind === "Ident" ? typeSubstMap.get(node.func.name) : null;
341
+ if (conv && node.args?.length === 1) {
342
+ return {
343
+ kind: "TypeConversion",
344
+ targetType: cloneAst(conv),
345
+ expr: substituteTypesInAst(
346
+ node.args[0],
347
+ typeSubstMap,
348
+ onGenericUsage,
349
+ genericTypes,
350
+ genericFuncs,
351
+ ),
352
+ _line: node._line,
353
+ };
354
+ }
355
+ // `make(S, n)` / `new(S)`: the type argument is a bare identifier.
356
+ if (
357
+ node.func?.kind === "Ident" &&
358
+ (node.func.name === "make" || node.func.name === "new") &&
359
+ node.args?.[0]?.kind === "Ident" &&
360
+ typeSubstMap.has(node.args[0].name)
361
+ ) {
362
+ node.args[0] = {
363
+ kind: "TypeExpr",
364
+ type: cloneAst(typeSubstMap.get(node.args[0].name)),
365
+ };
366
+ }
249
367
  if (node.func?.kind === "Ident") {
250
368
  let typeArgs = node._typeArgs ?? node.func._typeArgs;
251
369
  if (typeArgs) {
@@ -254,7 +372,7 @@ function substituteTypesInAst(
254
372
  if (name && typeSubstMap.has(name)) {
255
373
  return typeSubstMap.get(name);
256
374
  }
257
- return t;
375
+ return substituteInType(t, typeSubstMap);
258
376
  });
259
377
  const baseName = node.func.name;
260
378
  const sName = getSpecializedName(baseName, typeArgs);
@@ -504,9 +622,14 @@ export function monomorphise(programs, checker) {
504
622
  const genericFuncs = new Map();
505
623
  const genericTypes = new Map();
506
624
  const genericMethods = new Map(); // recvBaseName -> Array<MethodDecl>
625
+ // Template declaration -> its program; a specialization joins the program
626
+ // of its template, so a wasm package's instances stay wasm-package
627
+ // declarations even when a Go-source stdlib package is linked first.
628
+ const homeOf = new Map();
507
629
 
508
630
  for (const p of progs) {
509
631
  for (const d of p?.decls ?? []) {
632
+ homeOf.set(d, p);
510
633
  if (d.kind === "FuncDecl" && d.typeParams && d.typeParams.length > 0) {
511
634
  genericFuncs.set(d.name, d);
512
635
  } else if (
@@ -556,6 +679,7 @@ export function monomorphise(programs, checker) {
556
679
  }
557
680
  }
558
681
 
682
+ const typeInstances = new Map();
559
683
  const specializedFuncs = new Map();
560
684
  const specializedTypes = new Map();
561
685
  const specializedMethods = new Map();
@@ -583,6 +707,7 @@ export function monomorphise(programs, checker) {
583
707
  typeSubstMap.set(tp.name, typeToTypeNode(concrete));
584
708
  }
585
709
 
710
+ typeInstances.set(item.specializedName, item);
586
711
  const monoTypeDecl = cloneAst(genDecl);
587
712
  monoTypeDecl.name = item.specializedName;
588
713
  monoTypeDecl.typeParams = null;
@@ -593,7 +718,9 @@ export function monomorphise(programs, checker) {
593
718
  genericTypes,
594
719
  genericFuncs,
595
720
  );
721
+ rebindNamedResults(monoTypeDecl);
596
722
  specializedTypes.set(item.specializedName, monoTypeDecl);
723
+ homeOf.set(monoTypeDecl, homeOf.get(genDecl));
597
724
 
598
725
  // Specialize all methods declared on this generic type
599
726
  const methods = genericMethods.get(item.genericName) ?? [];
@@ -610,8 +737,10 @@ export function monomorphise(programs, checker) {
610
737
  genericTypes,
611
738
  genericFuncs,
612
739
  );
740
+ rebindNamedResults(monoMethod);
613
741
  const mKey = `${item.specializedName}.${monoMethod.name}`;
614
742
  specializedMethods.set(mKey, monoMethod);
743
+ homeOf.set(monoMethod, homeOf.get(m));
615
744
  }
616
745
  } else if (item.kind === "func") {
617
746
  const genDecl = genericFuncs.get(item.genericName);
@@ -634,7 +763,9 @@ export function monomorphise(programs, checker) {
634
763
  genericTypes,
635
764
  genericFuncs,
636
765
  );
766
+ rebindNamedResults(monoFuncDecl);
637
767
  specializedFuncs.set(item.specializedName, monoFuncDecl);
768
+ homeOf.set(monoFuncDecl, homeOf.get(genDecl));
638
769
  }
639
770
  }
640
771
 
@@ -686,15 +817,22 @@ export function monomorphise(programs, checker) {
686
817
 
687
818
  const targetProg = progs[0];
688
819
  if (targetProg) {
689
- targetProg.decls.push(...specializedTypes.values());
690
- targetProg.decls.push(...specializedMethods.values());
691
- targetProg.decls.push(...specializedFuncs.values());
820
+ for (const group of [
821
+ specializedTypes,
822
+ specializedMethods,
823
+ specializedFuncs,
824
+ ])
825
+ for (const d of group.values())
826
+ (homeOf.get(d) ?? targetProg).decls.push(d);
692
827
  }
693
828
 
694
829
  // 6. Typecheck the monomorphised program to annotate all concrete types
695
830
  const monoChecker = new TypeChecker();
696
831
  monoChecker.target = "wasm";
697
832
  monoChecker.pkgName = targetProg?.pkg?.name ?? "main";
833
+ // The programs were checked once already, where `//gofront:native` is
834
+ // limited to the standard library; this pass only re-annotates them.
835
+ monoChecker.nativesChecked = true;
698
836
  if (checker?.types) {
699
837
  for (const [name, type] of checker.types.entries()) {
700
838
  if (!monoChecker.types.has(name)) {
@@ -703,9 +841,26 @@ export function monomorphise(programs, checker) {
703
841
  }
704
842
  }
705
843
 
706
- for (const p of progs) {
707
- monoChecker.check(p);
708
- }
844
+ // One pass over all programs: declarations of every linked package are
845
+ // visible to the others (cross-package references are dequalified).
846
+ monoChecker.checkAll(progs);
847
+ nameInstances(monoChecker, typeInstances);
709
848
 
710
849
  return { programs: progs, checker: monoChecker };
711
850
  }
851
+
852
+ // Records Go's spelling of each generic instance (`Box[int]`) on its
853
+ // monomorphised type, which is named `Box$int`; `%T` prints the spelling.
854
+ function nameInstances(checker, instances) {
855
+ const spelling = {
856
+ has: (name) => instances.has(name),
857
+ get: (name) => {
858
+ const { genericName, typeArgs } = instances.get(name);
859
+ return `${genericName}[${typeArgs.map((a) => goTypeName(a, spelling)).join(",")}]`;
860
+ },
861
+ };
862
+ for (const name of instances.keys()) {
863
+ const type = checker.types.get(name);
864
+ if (type) type._goName = spelling.get(name);
865
+ }
866
+ }