gofront 1.8.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 (177) hide show
  1. package/README.md +3 -3
  2. package/package.json +5 -4
  3. package/src/backend/js/expressions.js +849 -371
  4. package/src/backend/js/index.js +241 -147
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +512 -2547
  7. package/src/backend/js/statements.js +506 -103
  8. package/src/backend/js/stdlib/index.js +45 -93
  9. package/src/backend/js/templ.js +32 -45
  10. package/src/backend/js/type-info.js +177 -13
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +63 -171
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +490 -965
  15. package/src/backend/wasm/emit-builtins.js +643 -256
  16. package/src/backend/wasm/emit-exprs.js +124 -57
  17. package/src/backend/wasm/emit-maps.js +17 -367
  18. package/src/backend/wasm/emit-stmts.js +325 -75
  19. package/src/backend/wasm/emit.js +104 -13
  20. package/src/backend/wasm/globals.js +47 -8
  21. package/src/backend/wasm/glue.js +2 -4
  22. package/src/backend/wasm/index.js +36 -530
  23. package/src/backend/wasm/method-expr.js +12 -1
  24. package/src/backend/wasm/module-emitter.js +92 -717
  25. package/src/backend/wasm/monomorph.js +103 -6
  26. package/src/backend/wasm/natives.js +596 -0
  27. package/src/backend/wasm/prescan.js +5 -153
  28. package/src/backend/wasm/prune-funcs.js +89 -0
  29. package/src/backend/wasm/stdlib/index.js +2 -32
  30. package/src/backend/wasm/types.js +68 -20
  31. package/src/backend/wasm/variadic.js +3 -3
  32. package/src/cli/cli-core.js +5 -1
  33. package/src/cli/test-runner.js +115 -342
  34. package/src/compiler.js +108 -130
  35. package/src/lexer/lexer.js +105 -11
  36. package/src/lexer/templ-lexer.js +61 -18
  37. package/src/lexer/tokens.js +1 -0
  38. package/src/link/stdlib.js +354 -132
  39. package/src/link/type-names.js +148 -0
  40. package/src/link/wasm.js +30 -6
  41. package/src/lower/bounds.js +153 -0
  42. package/src/lower/captures.js +92 -33
  43. package/src/lower/embedding.js +32 -3
  44. package/src/lower/errors-as.js +196 -0
  45. package/src/lower/fmt-formatters.js +905 -0
  46. package/src/lower/functions.js +2 -0
  47. package/src/lower/gen-types.js +274 -0
  48. package/src/lower/index.js +7 -1
  49. package/src/lower/json-codecs.js +228 -247
  50. package/src/lower/ownership.js +25 -7
  51. package/src/lower/reachability.js +69 -51
  52. package/src/lower/walk.js +12 -0
  53. package/src/parser/declarations.js +28 -5
  54. package/src/parser/expressions.js +86 -16
  55. package/src/parser/statements.js +1 -0
  56. package/src/parser/templ.js +44 -5
  57. package/src/parser/types.js +1 -0
  58. package/src/resolver.js +1 -2
  59. package/src/typechecker/assignability.js +124 -11
  60. package/src/typechecker/const-fold.js +70 -27
  61. package/src/typechecker/constants.js +32 -6
  62. package/src/typechecker/expressions.js +326 -98
  63. package/src/typechecker/index.js +208 -33
  64. package/src/typechecker/init-order.js +136 -40
  65. package/src/typechecker/operand-text.js +40 -0
  66. package/src/typechecker/resolve.js +192 -36
  67. package/src/typechecker/statements.js +122 -11
  68. package/src/typechecker/stdlib/excluded.js +9 -5
  69. package/src/typechecker/stdlib/index.js +25 -9
  70. package/src/typechecker/termination.js +10 -1
  71. package/src/typechecker/types.js +203 -573
  72. package/stdlib/bytes/buffer.go +479 -0
  73. package/stdlib/bytes/bytes.go +1010 -0
  74. package/stdlib/bytes/reader.go +161 -0
  75. package/stdlib/context/context.go +115 -0
  76. package/stdlib/crypto/rand/rand.go +34 -0
  77. package/stdlib/crypto/sha256/sha256.go +249 -0
  78. package/stdlib/encoding/base64/base64.go +331 -0
  79. package/stdlib/encoding/binary/binary.go +332 -0
  80. package/stdlib/encoding/hex/hex.go +140 -0
  81. package/stdlib/encoding/json/json.go +62 -0
  82. package/stdlib/errors/errors.go +174 -0
  83. package/stdlib/fmt/errors.go +110 -0
  84. package/stdlib/fmt/format.go +732 -0
  85. package/stdlib/fmt/print.go +1232 -0
  86. package/stdlib/gom/gom.go +293 -0
  87. package/stdlib/html/html.go +251 -0
  88. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  89. package/stdlib/internal/jsonrt/dec.go +171 -38
  90. package/stdlib/internal/jsonrt/enc.go +186 -36
  91. package/stdlib/internal/jsonrt/scanner.go +17 -8
  92. package/stdlib/io/io.go +157 -1
  93. package/stdlib/maps/maps.go +131 -0
  94. package/stdlib/math/bits/bits.go +507 -0
  95. package/stdlib/math/extra.go +16 -14
  96. package/stdlib/math/math.go +439 -0
  97. package/stdlib/math/rand/rand.go +297 -0
  98. package/stdlib/os/os.go +93 -0
  99. package/stdlib/path/filepath/filepath.go +47 -0
  100. package/stdlib/path/path.go +394 -0
  101. package/stdlib/regexp/regexp.go +231 -0
  102. package/stdlib/slices/slices.go +526 -0
  103. package/stdlib/slices/sort.go +209 -0
  104. package/stdlib/slices/zsort_cmp.go +480 -0
  105. package/stdlib/slices/zsort_ordered.go +482 -0
  106. package/stdlib/sort/sort.go +391 -452
  107. package/stdlib/sort/zsort_func.go +480 -0
  108. package/stdlib/sort/zsort_iface.go +480 -0
  109. package/stdlib/strconv/float.go +1699 -0
  110. package/stdlib/strconv/isprint.go +752 -0
  111. package/stdlib/strconv/quote.go +235 -50
  112. package/stdlib/strconv/strconv.go +616 -0
  113. package/stdlib/strings/builder.go +95 -0
  114. package/stdlib/strings/reader.go +163 -0
  115. package/stdlib/strings/replacer.go +102 -0
  116. package/stdlib/strings/strings.go +807 -0
  117. package/stdlib/sync/sync.go +268 -0
  118. package/stdlib/testing/async_js.go +61 -0
  119. package/stdlib/testing/benchmark.go +297 -0
  120. package/stdlib/testing/testing.go +523 -0
  121. package/stdlib/time/duration.go +233 -0
  122. package/stdlib/time/format.go +745 -0
  123. package/stdlib/time/parse.go +790 -0
  124. package/stdlib/time/sleep_js.go +63 -0
  125. package/stdlib/time/time.go +834 -0
  126. package/stdlib/unicode/unicode.go +141 -3
  127. package/stdlib/unicode/utf8/utf8.go +464 -0
  128. package/src/backend/js/fmt-runtime.js +0 -573
  129. package/src/backend/js/stdlib/base64.js +0 -12
  130. package/src/backend/js/stdlib/binary.js +0 -102
  131. package/src/backend/js/stdlib/bits.js +0 -119
  132. package/src/backend/js/stdlib/builder.js +0 -98
  133. package/src/backend/js/stdlib/bytes.js +0 -368
  134. package/src/backend/js/stdlib/errors.js +0 -45
  135. package/src/backend/js/stdlib/fmt.js +0 -517
  136. package/src/backend/js/stdlib/gom.js +0 -155
  137. package/src/backend/js/stdlib/hex.js +0 -17
  138. package/src/backend/js/stdlib/html.js +0 -20
  139. package/src/backend/js/stdlib/io.js +0 -137
  140. package/src/backend/js/stdlib/json.js +0 -1167
  141. package/src/backend/js/stdlib/maps.js +0 -37
  142. package/src/backend/js/stdlib/math.js +0 -85
  143. package/src/backend/js/stdlib/os.js +0 -13
  144. package/src/backend/js/stdlib/path.js +0 -48
  145. package/src/backend/js/stdlib/rand.js +0 -32
  146. package/src/backend/js/stdlib/regexp.js +0 -54
  147. package/src/backend/js/stdlib/sha256.js +0 -12
  148. package/src/backend/js/stdlib/shared.js +0 -17
  149. package/src/backend/js/stdlib/simd.js +0 -34
  150. package/src/backend/js/stdlib/slices.js +0 -107
  151. package/src/backend/js/stdlib/sort.js +0 -30
  152. package/src/backend/js/stdlib/strconv.js +0 -79
  153. package/src/backend/js/stdlib/strings.js +0 -301
  154. package/src/backend/js/stdlib/sync.js +0 -13
  155. package/src/backend/js/stdlib/testing.js +0 -41
  156. package/src/backend/js/stdlib/time.js +0 -152
  157. package/src/backend/js/stdlib/unicode.js +0 -25
  158. package/src/backend/js/stdlib/utf8.js +0 -26
  159. package/src/backend/wasm/stdlib/bytes.js +0 -6716
  160. package/src/backend/wasm/stdlib/core.js +0 -10278
  161. package/src/backend/wasm/stdlib/io.js +0 -3578
  162. package/src/backend/wasm/stdlib/packages.js +0 -2402
  163. package/src/backend/wasm/stdlib/pure.js +0 -720
  164. package/src/backend/wasm/stdlib/time.js +0 -2229
  165. package/src/typechecker/stdlib/core.js +0 -1079
  166. package/src/typechecker/stdlib/extended.js +0 -1210
  167. package/stdlib/bytes/iter.go +0 -192
  168. package/stdlib/bytes/search.go +0 -240
  169. package/stdlib/bytes/split.go +0 -218
  170. package/stdlib/errors/overlay.go +0 -12
  171. package/stdlib/maps/iter.go +0 -65
  172. package/stdlib/slices/extra.go +0 -73
  173. package/stdlib/slices/iter.go +0 -113
  174. package/stdlib/strings/extra.go +0 -35
  175. package/stdlib/strings/iter.go +0 -122
  176. package/stdlib/sync/extra.go +0 -105
  177. package/stdlib/unicode/utf8/bytes.go +0 -239
@@ -2,8 +2,7 @@
2
2
  // ModuleEmitter: Module IR builder that registers types, imports, globals and functions.
3
3
 
4
4
  import { wTypeKey } from "./boundary.js";
5
- import { hasErrorUsage, importsAnyOf } from "./prescan.js";
6
- import { BINARY_MATH_IMPORTS } from "./stdlib/index.js";
5
+ import { hasErrorUsage } from "./prescan.js";
7
6
  import {
8
7
  ERROR_STRUCT,
9
8
  getFuncSignature,
@@ -14,215 +13,6 @@ import {
14
13
  toWasmType,
15
14
  } from "./types.js";
16
15
 
17
- const ERROR_PRODUCING_PKGS = new Set([
18
- "errors",
19
- "fmt",
20
- "strconv",
21
- "path",
22
- "path/filepath",
23
- "io",
24
- "os",
25
- "strings",
26
- "bytes",
27
- "time",
28
- "sync",
29
- "crypto/rand",
30
- "rand",
31
- "crypto/sha256",
32
- "sha256",
33
- "encoding/binary",
34
- "binary",
35
- "encoding/hex",
36
- "hex",
37
- "encoding/base64",
38
- "base64",
39
- "math/bits",
40
- "bits",
41
- ]);
42
- // Packages whose calls lower to the `env.*` imports in STDLIB_IMPORTS (the
43
- // matching JS lives in WASM_STDLIB_JS). Only modules importing one of them
44
- // declare the imports and ship that JS block.
45
- const STDLIB_ENV_PKGS = new Set([
46
- "strings",
47
- "strconv",
48
- "unicode/utf8",
49
- "fmt",
50
- "testing",
51
- "unicode",
52
- "math/rand",
53
- "path",
54
- "path/filepath",
55
- "html",
56
- "bytes",
57
- "io",
58
- "os",
59
- "time",
60
- "sync",
61
- "crypto/rand",
62
- "rand",
63
- "crypto/sha256",
64
- "sha256",
65
- "encoding/binary",
66
- "binary",
67
- "encoding/hex",
68
- "hex",
69
- "encoding/base64",
70
- "base64",
71
- "math/bits",
72
- "bits",
73
- ]);
74
-
75
- // [name, params, results] for `env.*` imports backing stdlib calls; the JS
76
- // side lives in WASM_STDLIB_JS (boundary.js). All are registered eagerly
77
- // (when any STDLIB_ENV_PKGS package is imported) because the import table is
78
- // locked before function bodies are emitted.
79
- const S = "externref";
80
- const STDLIB_IMPORTS = [
81
- // strings
82
- ["str_trim", [S, S], [S]],
83
- ["str_trim_left", [S, S], [S]],
84
- ["str_trim_right", [S, S], [S]],
85
- ["str_trim_prefix", [S, S], [S]],
86
- ["str_trim_suffix", [S, S], [S]],
87
- ["str_cut", [S, S], ["i32"]],
88
- ["str_cut_before", [], [S]],
89
- ["str_cut_after", [], [S]],
90
- ["str_cut_prefix", [S, S], ["i32"]],
91
- ["str_cut_suffix", [S, S], ["i32"]],
92
- ["str_replace", [S, S, S, "i32"], [S]],
93
- ["str_contains_rune", [S, "i32"], ["i32"]],
94
- ["str_contains_any", [S, S], ["i32"]],
95
- ["str_index_byte", [S, "i32"], ["i32"]],
96
- ["str_index_rune", [S, "i32"], ["i32"]],
97
- ["str_index_any", [S, S], ["i32"]],
98
- ["str_last_index_byte", [S, "i32"], ["i32"]],
99
- ["str_last_index_any", [S, S], ["i32"]],
100
- ["str_title", [S], [S]],
101
- ["str_split", [S, S], ["i32"]],
102
- ["str_split_n", [S, S, "i32"], ["i32"]],
103
- ["str_split_after", [S, S], ["i32"]],
104
- ["str_split_after_n", [S, S, "i32"], ["i32"]],
105
- ["str_fields", [S], ["i32"]],
106
- ["str_part", ["i32"], [S]],
107
- ["str_replacer_init", [S], []],
108
- ["str_replacer_add", [S, S], []],
109
- ["str_replacer_run", [], [S]],
110
- // strconv
111
- ["strconv_atoi", [S], ["i64"]],
112
- ["strconv_parse_int", [S, "i32", "i32"], ["i64"]],
113
- ["strconv_parse_float", [S], ["f64"]],
114
- ["strconv_parse_bool", [S], ["i32"]],
115
- ["strconv_err", [], [S]],
116
- ["strconv_err_kind", [], ["i32"]],
117
- ["strconv_format_float", ["f64", "i32", "i32", "i32"], [S]],
118
- ["strconv_format_int", ["i64", "i32"], [S]],
119
- ["strconv_format_uint", ["i64", "i32"], [S]],
120
- ["strconv_parse_uint", [S, "i32", "i32"], ["i64"]],
121
- ["strconv_quote", [S], [S]],
122
- ["strconv_unquote", [S], [S]],
123
- // unicode/utf8
124
- ["utf8_rune_count", [S], ["i32"]],
125
- ["utf8_rune_len", ["i32"], ["i32"]],
126
- ["utf8_valid_string", [S], ["i32"]],
127
- ["utf8_decode_rune", [S, "i32"], ["i32"]],
128
- ["utf8_decode_size", [], ["i32"]],
129
- ["utf8_full_rune", [S], ["i32"]],
130
- // fmt (arguments travel through the testing_arg_* buffer)
131
- ["fmt_sprintf", [S], [S]],
132
- ["fmt_printf", [S], []],
133
- ["fmt_sprint", ["i32"], [S]],
134
- ["fmt_print", ["i32"], []],
135
- ["fmt_print_raw", [S], []],
136
- ["fmt_format_v", [S], [S]],
137
- ["fmt_sscan_init", [S, "i32"], ["i32"]],
138
- ["fmt_sscanf_init", [S, S], ["i32"]],
139
- ["fmt_sscan_has_err", [], ["i32"]],
140
- ["fmt_sscan_err_msg", [], [S]],
141
- ["fmt_sscan_token_str", ["i32"], [S]],
142
- ["fmt_sscan_token_i64", ["i32"], ["i64"]],
143
- ["fmt_sscan_token_f64", ["i32"], ["f64"]],
144
- ["fmt_sscan_token_bool", ["i32"], ["i32"]],
145
- // testing.T.Run: the harness calls back into the exported __testing_run_cb
146
- ["testing_run", [S, S, "anyref"], ["i32"]],
147
- ["testing_cleanup", [S, "anyref"], []],
148
- ["testing_n", [S], ["i64"]],
149
- ["testing_elapsed", [S], ["i64"]],
150
- ["testing_context", [S], [S]],
151
- ["testing_output", [S], [S]],
152
- // unicode
153
- ["unicode_is_letter", ["i32"], ["i32"]],
154
- ["unicode_is_digit", ["i32"], ["i32"]],
155
- ["unicode_is_space", ["i32"], ["i32"]],
156
- ["unicode_is_upper", ["i32"], ["i32"]],
157
- ["unicode_is_lower", ["i32"], ["i32"]],
158
- ["unicode_is_punct", ["i32"], ["i32"]],
159
- ["unicode_is_control", ["i32"], ["i32"]],
160
- ["unicode_is_print", ["i32"], ["i32"]],
161
- ["unicode_is_graphic", ["i32"], ["i32"]],
162
- ["unicode_to_upper", ["i32"], ["i32"]],
163
- ["unicode_to_lower", ["i32"], ["i32"]],
164
- // html
165
- ["html_escape", [S], [S]],
166
- ["html_unescape", [S], [S]],
167
- // path
168
- ["path_base", [S], [S]],
169
- ["path_dir", [S], [S]],
170
- ["path_ext", [S], [S]],
171
- ["path_is_abs", [S], ["i32"]],
172
- ["path_clean", [S], [S]],
173
- ["path_split", [S], []],
174
- ["path_split_dir", [], [S]],
175
- ["path_split_file", [], [S]],
176
- ["path_join_init", [], []],
177
- ["path_join_push", [S], []],
178
- ["path_join_run", [], [S]],
179
- ["path_match", [S, S], ["i32"]],
180
- ["path_match_has_err", [], ["i32"]],
181
- ["bytes_trim", [S, S, "i32", "i32"], []],
182
- ["bytes_trim_start", [], ["i32"]],
183
- ["bytes_trim_end", [], ["i32"]],
184
- // time
185
- ["time_now_ms", [], ["f64"]],
186
- ["time_timezone_offset", ["f64"], ["i32"]],
187
- ["time_parse", [S, S], ["f64"]],
188
- ["time_parse_err", [], [S]],
189
- ["time_parse_offset", [], ["i32"]],
190
- ["time_parse_sub_ns", [], ["i32"]],
191
- [
192
- "time_format",
193
- ["i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", S],
194
- [S],
195
- ],
196
- ["time_duration_string", ["i64"], [S]],
197
- ["time_parse_duration", [S], ["i64"]],
198
- ["time_parse_duration_err", [], [S]],
199
- ["time_month_string", ["i32"], [S]],
200
- ["time_weekday_string", ["i32"], [S]],
201
- // raw binary buffer for crypto/rand, crypto/sha256, hex, base64
202
- ["raw_bytes_init", ["i32"], []],
203
- ["raw_bytes_push", ["i32"], []],
204
- ["raw_bytes_len", [], ["i32"]],
205
- ["raw_bytes_get", ["i32"], ["i32"]],
206
- // crypto/rand
207
- ["crypto_rand_fill", ["i32"], ["i32"]],
208
- // crypto/sha256
209
- ["crypto_sha256_sum", [], ["i32"]],
210
- // encoding/hex
211
- ["hex_encode_to_string", [], [S]],
212
- ["hex_decode_string", [S], ["i32"]],
213
- ["hex_get_err", [], [S]],
214
- // encoding/base64
215
- ["base64_encode_to_string", ["i32"], [S]],
216
- ["base64_decode_string", ["i32", S], ["i32"]],
217
- ["base64_get_err", [], [S]],
218
- ["bits_div32", ["i32", "i32", "i32"], ["i32"]],
219
- ["bits_div32_rem", [], ["i32"]],
220
- ["bits_rem32", ["i32", "i32", "i32"], ["i32"]],
221
- ["bits_div64", ["i64", "i64", "i64"], ["i64"]],
222
- ["bits_div64_rem", [], ["i64"]],
223
- ["bits_rem64", ["i64", "i64", "i64"], ["i64"]],
224
- ];
225
-
226
16
  export class ModuleEmitter {
227
17
  constructor(checker, lowerResult = null, programs = [], options = {}) {
228
18
  this.checker = checker;
@@ -230,6 +20,7 @@ export class ModuleEmitter {
230
20
  // Local package names whose code is linked into this module; selectors
231
21
  // like `mathx.NewVec3` are de-qualified to `NewVec3` by the emitter.
232
22
  this.bundledPackages = options.bundledPackages ?? new Set();
23
+ this.natives = options.natives !== false; // replace native calls with host code
233
24
  this.constCache = new Map(); // name -> BasicLit (package-level literal consts)
234
25
  this.nonLiteralConsts = new Set(); // package-level consts the backend cannot evaluate yet
235
26
 
@@ -246,6 +37,7 @@ export class ModuleEmitter {
246
37
  this.arrayTypes = new Map(); // wType key -> array info
247
38
  this.sliceTypes = new Map(); // wType key -> slice info
248
39
  this.sliceTypesByIndex = new Map(); // typeIndex -> slice info
40
+ this.taggedSliceTypes = new Map(); // Go slice type key -> tagged info
249
41
  this.mapTypes = new Map(); // wType key -> map info
250
42
  this.mapTypesByIndex = new Map(); // typeIndex -> map info
251
43
  this.mapBucketsType = null; // shared (array (mut i32))
@@ -275,10 +67,7 @@ export class ModuleEmitter {
275
67
  // `errors.New` / `fmt.Errorf` / strconv parse failures allocate the
276
68
  // runtime's own error struct; it joins the struct rec group so the
277
69
  // `error.Error` dispatcher can `ref.test` it like any user type.
278
- this.hasErrorType =
279
- importsAnyOf(programs, ERROR_PRODUCING_PKGS) || hasErrorUsage(programs);
280
- this.usesStdlibEnv = importsAnyOf(programs, STDLIB_ENV_PKGS);
281
- this.importsTesting = importsAnyOf(programs, ["testing"]);
70
+ this.hasErrorType = hasErrorUsage(programs);
282
71
 
283
72
  if (programs && programs.length > 0) {
284
73
  this.initTypes(programs);
@@ -288,6 +77,26 @@ export class ModuleEmitter {
288
77
  this._initRuntimeImports();
289
78
  }
290
79
 
80
+ // The runtime error struct is not declared in Go source: give the checker a
81
+ // named type with its method set (`Error() string`) so type assertions to
82
+ // `interface{ Error() string }` find it as a candidate.
83
+ _registerRuntimeErrorType() {
84
+ const types = this.checker?.types;
85
+ if (!types || types.has(ERROR_STRUCT)) return;
86
+ const STRING = { kind: "basic", name: "string" };
87
+ types.set(ERROR_STRUCT, {
88
+ kind: "named",
89
+ name: ERROR_STRUCT,
90
+ underlying: {
91
+ kind: "struct",
92
+ fields: new Map(),
93
+ methods: new Map([
94
+ ["Error", { kind: "func", params: [], returns: [STRING] }],
95
+ ]),
96
+ },
97
+ });
98
+ }
99
+
291
100
  initTypes(programs) {
292
101
  const progs = Array.isArray(programs) ? programs : [programs];
293
102
  const rawStructs = [];
@@ -295,15 +104,13 @@ export class ModuleEmitter {
295
104
  const aliases = []; // qualified key (pkg.T) -> unqualified struct name
296
105
 
297
106
  if (this.hasErrorType) {
107
+ this._registerRuntimeErrorType();
298
108
  seen.add(ERROR_STRUCT);
299
109
  rawStructs.push({
300
110
  name: ERROR_STRUCT,
301
111
  structType: {
302
112
  kind: "struct",
303
- fields: new Map([
304
- ["msg", { kind: "basic", name: "string" }],
305
- ["cause", { kind: "basic", name: "any" }],
306
- ]),
113
+ fields: new Map([["msg", { kind: "basic", name: "string" }]]),
307
114
  },
308
115
  });
309
116
  }
@@ -332,11 +139,6 @@ export class ModuleEmitter {
332
139
  for (const [key, t] of this.checker.types.entries()) {
333
140
  if (t.kind === "named" && t.underlying?.kind === "struct") {
334
141
  const name = t.name ?? key;
335
- if (
336
- name.startsWith("testing.") &&
337
- (!this.importsTesting || name !== "testing.BenchmarkResult")
338
- )
339
- continue;
340
142
  if (!seen.has(name)) {
341
143
  seen.add(name);
342
144
  rawStructs.push({ name, structType: t.underlying });
@@ -416,8 +218,16 @@ export class ModuleEmitter {
416
218
  });
417
219
  fieldIndexMap.set(n, fIdx);
418
220
  if (f.embedded) {
221
+ // The embedded type, when it differs from the field
222
+ // name (`Mutex$$sync` for the field `Mutex`).
223
+ const ref =
224
+ f.type?.kind === "PointerType"
225
+ ? f.type.base?.name
226
+ : f.type?.name;
227
+ const typeName = this.checker?.types?.get(ref)?.name;
419
228
  embeds.push({
420
229
  name: n,
230
+ ...(typeName && typeName !== n && { typeName }),
421
231
  fieldIndex: fIdx,
422
232
  });
423
233
  }
@@ -524,9 +334,11 @@ export class ModuleEmitter {
524
334
  const typeEntry = {
525
335
  form: "struct",
526
336
  name: typeName,
337
+ // Mutable so the facade's per-field setters for an exported struct
338
+ // that holds a complex value validate.
527
339
  fields: [
528
- { type: elemWType, mutable: false },
529
- { type: elemWType, mutable: false },
340
+ { type: elemWType, mutable: true },
341
+ { type: elemWType, mutable: true },
530
342
  ],
531
343
  };
532
344
  this._pushType(typeEntry);
@@ -704,6 +516,10 @@ export class ModuleEmitter {
704
516
  const typeIndex = this._getTotalTypeCount();
705
517
  const typeEntry = {
706
518
  form: "struct",
519
+ // Slice types are open: each defined slice type, and each Go type among
520
+ // the 32-bit-or-smaller elements, gets a tagged subtype when it
521
+ // reaches an interface.
522
+ sub: true,
707
523
  fields: [
708
524
  {
709
525
  type: {
@@ -750,6 +566,43 @@ export class ModuleEmitter {
750
566
  return sliceInfo;
751
567
  }
752
568
 
569
+ // The subtype of the slice struct a value of Go slice type `sliceGoType`
570
+ // takes inside an interface. Slices of booleans and small integers share
571
+ // one WebAssembly type, so the extra tag field (a nullable ref to a struct
572
+ // with one immutable i32 field per tag index) is what tells `[]byte` from
573
+ // `[]bool` and `json.RawMessage` from `[]byte` in a type test.
574
+ getTaggedSliceType(sliceGoType, elemGoType) {
575
+ const key = goTypeKey(sliceGoType);
576
+ const known = this.taggedSliceTypes.get(key);
577
+ if (known) return known;
578
+ const base = this.getSliceType(elemGoType);
579
+ const tagIndex = this.taggedSliceTypes.size + 1;
580
+ const tagTypeIndex = this._getTotalTypeCount();
581
+ this._pushType({
582
+ form: "struct",
583
+ fields: Array.from({ length: tagIndex }, () => ({
584
+ type: "i32",
585
+ mutable: false,
586
+ })),
587
+ });
588
+ const typeIndex = this._getTotalTypeCount();
589
+ this._pushType({
590
+ form: "struct",
591
+ sub: true,
592
+ superTypeIndex: base.typeIndex,
593
+ fields: [
594
+ ...base.typeEntry.fields,
595
+ {
596
+ type: { kind: "ref", nullable: true, typeIndex: tagTypeIndex },
597
+ mutable: false,
598
+ },
599
+ ],
600
+ });
601
+ const info = { key, typeIndex, tagTypeIndex, base, goType: sliceGoType };
602
+ this.taggedSliceTypes.set(key, info);
603
+ return info;
604
+ }
605
+
753
606
  getSliceTypeByIndex(typeIndex) {
754
607
  return this.sliceTypesByIndex?.get(typeIndex) ?? null;
755
608
  }
@@ -848,17 +701,12 @@ export class ModuleEmitter {
848
701
  clearFuncName: `__map_clear_${suffix}`,
849
702
  keysFuncName: `__map_keys_${suffix}`,
850
703
  valuesFuncName: `__map_values_${suffix}`,
851
- cloneFuncName: `__map_clone_${suffix}`,
852
704
  };
853
705
  this.mapTypes.set(key, mapInfo);
854
706
  this.mapTypesByIndex.set(mapTypeIndex, mapInfo);
855
707
  return mapInfo;
856
708
  }
857
709
 
858
- getMapTypeByIndex(typeIndex) {
859
- return this.mapTypesByIndex?.get(typeIndex) ?? null;
860
- }
861
-
862
710
  getClosureType(goType) {
863
711
  const sig = getFuncSignature(goType, this.checker);
864
712
  const paramWTypes = sig.params
@@ -971,19 +819,6 @@ export class ModuleEmitter {
971
819
  this.getStringFromCodePointImportIndex(); // env.str_from_code_point
972
820
  this.getStringCodePointAtImportIndex(); // env.str_code_point_at
973
821
  this.getStringHashImportIndex(); // env.str_hash
974
- this.getStringToUpperImportIndex();
975
- this.getStringToLowerImportIndex();
976
- this.getStringTrimSpaceImportIndex();
977
- this.getStringContainsImportIndex();
978
- this.getStringHasPrefixImportIndex();
979
- this.getStringHasSuffixImportIndex();
980
- this.getStringIndexImportIndex();
981
- this.getStringLastIndexImportIndex();
982
- this.getStringRepeatImportIndex();
983
- this.getStringReplaceAllImportIndex();
984
- this.getStringEqualFoldImportIndex();
985
- this.getStringCountImportIndex();
986
- this.getStringToValidUTF8ImportIndex();
987
822
  this.getStrFromI64ImportIndex();
988
823
  this.getStrFromI32ImportIndex();
989
824
  this.getStrFromF64ImportIndex();
@@ -993,35 +828,6 @@ export class ModuleEmitter {
993
828
  this.getBytesToStrInitImportIndex();
994
829
  this.getBytesToStrPushImportIndex();
995
830
  this.getBytesToStrFinishImportIndex();
996
- this.getTestingCallImportIndex();
997
- this.getTestingNameImportIndex();
998
- this.getTestingFlagImportIndex();
999
- for (const t of ["i32", "i64", "f32", "f64", "externref", "anyref"]) {
1000
- this.getTestingArgImportIndex(t, false);
1001
- }
1002
- this.getTestingArgImportIndex("i32", true);
1003
- this.getTestingArgErrImportIndex();
1004
- this.getTestingArgSpreadImportIndex();
1005
- this.getTestingArgU64ImportIndex();
1006
- this.getFmtArgTypeImportIndex();
1007
- this.getFmtStructTypeImportIndex();
1008
- this.getFmtNewArrayIndex();
1009
- this.getFmtArrayPushIndex();
1010
- this.getFmtNewMapIndex();
1011
- this.getFmtMapSetIndex();
1012
- this.getFmtNewStructIndex();
1013
- this.getFmtStructSetIndex();
1014
- this.getFmtBoxI32Index();
1015
- this.getFmtBoxI64Index();
1016
- this.getFmtBoxF64Index();
1017
- this.getFmtBoxBoolIndex();
1018
- this.getFmtNewBoxIndex();
1019
- this.getFmtNewStringerIndex();
1020
- if (this.usesStdlibEnv) {
1021
- for (const [name, params, results] of STDLIB_IMPORTS) {
1022
- this.getOrAddFuncImport("env", name, params, results);
1023
- }
1024
- }
1025
831
 
1026
832
  // Logging built-ins
1027
833
  this.getPrintlnEmptyIndex(); // env.println_empty
@@ -1032,30 +838,6 @@ export class ModuleEmitter {
1032
838
  }
1033
839
  this.getLogImportIndex("i32", false, true); // env.print_bool
1034
840
  this.getLogImportIndex("i32", true, true); // env.println_bool
1035
-
1036
- // Math built-ins
1037
- const unaryMath = [
1038
- "sin",
1039
- "cos",
1040
- "tan",
1041
- "asin",
1042
- "acos",
1043
- "atan",
1044
- "exp",
1045
- "log",
1046
- "log2",
1047
- "log10",
1048
- "round",
1049
- "cbrt",
1050
- "log1p",
1051
- "expm1",
1052
- ];
1053
- for (const m of unaryMath) {
1054
- this.getMathImportIndex(m, false);
1055
- }
1056
- for (const m of BINARY_MATH_IMPORTS) {
1057
- this.getMathImportIndex(m, true);
1058
- }
1059
841
  }
1060
842
 
1061
843
  _initPanicTag() {
@@ -1137,93 +919,6 @@ export class ModuleEmitter {
1137
919
  return gIdx;
1138
920
  }
1139
921
 
1140
- getRandStateGlobalIndex() {
1141
- if (this.randStateGlobalIndex !== undefined) {
1142
- return this.randStateGlobalIndex;
1143
- }
1144
- const gIdx = this.globals.length;
1145
- this.globals.push({
1146
- type: "i64",
1147
- mutable: true,
1148
- init: [{ op: "i64.const", value: 1n }],
1149
- });
1150
- this.randStateGlobalIndex = gIdx;
1151
- return gIdx;
1152
- }
1153
-
1154
- getStrconvErrGlobalIndex(field) {
1155
- if (!this.strconvErrGlobals) this.strconvErrGlobals = new Map();
1156
- if (this.strconvErrGlobals.has(field)) {
1157
- return this.strconvErrGlobals.get(field);
1158
- }
1159
- const gIdx = this.globals.length;
1160
- this.globals.push({
1161
- type: "anyref",
1162
- mutable: true,
1163
- init: [{ op: "ref.null", heapType: "any" }],
1164
- });
1165
- this.strconvErrGlobals.set(field, gIdx);
1166
- return gIdx;
1167
- }
1168
-
1169
- getPathErrGlobalIndex(field) {
1170
- if (!this.pathErrGlobals) this.pathErrGlobals = new Map();
1171
- if (this.pathErrGlobals.has(field)) {
1172
- return this.pathErrGlobals.get(field);
1173
- }
1174
- const gIdx = this.globals.length;
1175
- this.globals.push({
1176
- type: "anyref",
1177
- mutable: true,
1178
- init: [{ op: "ref.null", heapType: "any" }],
1179
- });
1180
- this.pathErrGlobals.set(field, gIdx);
1181
- return gIdx;
1182
- }
1183
-
1184
- getIoErrGlobalIndex(field) {
1185
- if (!this.ioErrGlobals) this.ioErrGlobals = new Map();
1186
- if (this.ioErrGlobals.has(field)) {
1187
- return this.ioErrGlobals.get(field);
1188
- }
1189
- const gIdx = this.globals.length;
1190
- this.globals.push({
1191
- type: "anyref",
1192
- mutable: true,
1193
- init: [{ op: "ref.null", heapType: "any" }],
1194
- });
1195
- this.ioErrGlobals.set(field, gIdx);
1196
- return gIdx;
1197
- }
1198
-
1199
- getIoDiscardGlobalIndex() {
1200
- if (this.ioDiscardGlobalIndex !== undefined) {
1201
- return this.ioDiscardGlobalIndex;
1202
- }
1203
- this.getStructType("io.discard");
1204
- const gIdx = this.globals.length;
1205
- this.globals.push({
1206
- type: "anyref",
1207
- mutable: true,
1208
- init: [{ op: "ref.null", heapType: "any" }],
1209
- });
1210
- this.ioDiscardGlobalIndex = gIdx;
1211
- return gIdx;
1212
- }
1213
-
1214
- getOsGlobalIndex(field) {
1215
- this.osGlobals ??= new Map();
1216
- if (this.osGlobals.has(field)) return this.osGlobals.get(field);
1217
- const gIdx = this.globals.length;
1218
- this.globals.push({
1219
- type: "anyref",
1220
- mutable: true,
1221
- init: [{ op: "ref.null", heapType: "any" }],
1222
- });
1223
- this.osGlobals.set(field, gIdx);
1224
- return gIdx;
1225
- }
1226
-
1227
922
  getDeferNodeTypeIndex() {
1228
923
  if (this.deferNodeTypeIndex !== undefined) {
1229
924
  return this.deferNodeTypeIndex;
@@ -1361,190 +1056,8 @@ export class ModuleEmitter {
1361
1056
  return this.getOrAddFuncImport("env", "println_empty", [], []);
1362
1057
  }
1363
1058
 
1364
- getFmtNewArrayIndex() {
1365
- return this.getOrAddFuncImport("env", "fmt_new_array", [], ["externref"]);
1366
- }
1367
-
1368
- getFmtArrayPushIndex() {
1369
- return this.getOrAddFuncImport(
1370
- "env",
1371
- "fmt_array_push",
1372
- ["externref", "externref"],
1373
- [],
1374
- );
1375
- }
1376
-
1377
- getFmtNewMapIndex() {
1378
- return this.getOrAddFuncImport("env", "fmt_new_map", [], ["externref"]);
1379
- }
1380
-
1381
- getFmtMapSetIndex() {
1382
- return this.getOrAddFuncImport(
1383
- "env",
1384
- "fmt_map_set",
1385
- ["externref", "externref", "externref"],
1386
- [],
1387
- );
1388
- }
1389
-
1390
- getFmtNewStringerIndex() {
1391
- return this.getOrAddFuncImport(
1392
- "env",
1393
- "fmt_new_stringer",
1394
- ["externref", "externref", "i32"],
1395
- ["externref"],
1396
- );
1397
- }
1398
-
1399
- getFmtNewStructIndex() {
1400
- return this.getOrAddFuncImport(
1401
- "env",
1402
- "fmt_new_struct",
1403
- ["anyref", "i32"],
1404
- ["externref"],
1405
- );
1406
- }
1407
-
1408
- // Names the Go type of a struct built for fmt (`%T`, `%#v` of an any).
1409
- getFmtStructTypeImportIndex() {
1410
- return this.getOrAddFuncImport(
1411
- "env",
1412
- "fmt_struct_type",
1413
- ["externref", "i32"],
1414
- [],
1415
- );
1416
- }
1417
-
1418
- getFmtStructSetIndex() {
1419
- return this.getOrAddFuncImport(
1420
- "env",
1421
- "fmt_struct_set",
1422
- ["externref", "i32", "externref"],
1423
- [],
1424
- );
1425
- }
1426
-
1427
- getFmtBoxI32Index() {
1428
- return this.getOrAddFuncImport(
1429
- "env",
1430
- "fmt_box_i32",
1431
- ["i32"],
1432
- ["externref"],
1433
- );
1434
- }
1435
-
1436
- getFmtBoxI64Index() {
1437
- return this.getOrAddFuncImport(
1438
- "env",
1439
- "fmt_box_i64",
1440
- ["i64"],
1441
- ["externref"],
1442
- );
1443
- }
1444
-
1445
- // Registered only for programs whose fmt operands may hold a uint64
1446
- // (see scanFmtU64), so other modules keep their import table.
1447
- getFmtBoxU64Index() {
1448
- return this.getOrAddFuncImport(
1449
- "env",
1450
- "fmt_box_u64",
1451
- ["i64"],
1452
- ["externref"],
1453
- );
1454
- }
1455
-
1456
- getFmtBoxF64Index() {
1457
- return this.getOrAddFuncImport(
1458
- "env",
1459
- "fmt_box_f64",
1460
- ["f64"],
1461
- ["externref"],
1462
- );
1463
- }
1464
-
1465
- getFmtBoxBoolIndex() {
1466
- return this.getOrAddFuncImport(
1467
- "env",
1468
- "fmt_box_bool",
1469
- ["i32"],
1470
- ["externref"],
1471
- );
1472
- }
1473
-
1474
- getFmtNewBoxIndex() {
1475
- return this.getOrAddFuncImport("env", "fmt_new_box", [], ["externref"]);
1476
- }
1477
-
1478
- // `*testing.T` method calls: args are pushed one by one to a JS-side
1479
- // buffer, then `testing_call(t, methodNameStrIdx)` invokes the method.
1480
- getTestingArgImportIndex(wType, isBool = false) {
1481
- if (isBool)
1482
- return this.getOrAddFuncImport("env", "testing_arg_bool", ["i32"], []);
1483
- const suffix =
1484
- wType === "externref" ? "str" : wType === "anyref" ? "any" : wType;
1485
- if (!["i32", "i64", "f32", "f64", "str", "any"].includes(suffix)) {
1486
- throw new Error(
1487
- "only primitive, string, error and any arguments are supported for fmt and testing.T calls in wasm packages (format slices/structs field by field)",
1488
- );
1489
- }
1490
- return this.getOrAddFuncImport(
1491
- "env",
1492
- `testing_arg_${suffix}`,
1493
- [suffix === "str" ? "externref" : suffix === "any" ? "anyref" : wType],
1494
- [],
1495
- );
1496
- }
1497
-
1498
- // Error operands of fmt.Sprint/Print/Append: a non-string for the host.
1499
- getTestingArgSpreadImportIndex() {
1500
- return this.getOrAddFuncImport(
1501
- "env",
1502
- "testing_arg_spread",
1503
- ["externref"],
1504
- [],
1505
- );
1506
- }
1507
-
1508
- // An unsigned 64-bit operand: the host reinterprets the i64 as unsigned.
1509
- getTestingArgU64ImportIndex() {
1510
- return this.getOrAddFuncImport("env", "testing_arg_u64", ["i64"], []);
1511
- }
1512
-
1513
- // Tags the last operand in the argument buffer with the static type
1514
- // descriptor (JSON) held in string table entry `i32`, for `%T` and `%#v`.
1515
- getFmtArgTypeImportIndex() {
1516
- return this.getOrAddFuncImport("env", "fmt_arg_type", ["i32"], []);
1517
- }
1518
-
1519
- getTestingArgErrImportIndex() {
1520
- return this.getOrAddFuncImport("env", "testing_arg_err", ["externref"], []);
1521
- }
1522
-
1523
- getTestingCallImportIndex() {
1524
- return this.getOrAddFuncImport(
1525
- "env",
1526
- "testing_call",
1527
- ["externref", "i32"],
1528
- [],
1529
- );
1530
- }
1531
-
1532
- getTestingNameImportIndex() {
1533
- return this.getOrAddFuncImport(
1534
- "env",
1535
- "testing_name",
1536
- ["externref"],
1537
- ["externref"],
1538
- );
1539
- }
1540
-
1541
- getTestingFlagImportIndex() {
1542
- return this.getOrAddFuncImport(
1543
- "env",
1544
- "testing_flag",
1545
- ["externref", "i32"],
1546
- ["i32"],
1547
- );
1059
+ getPrintResetIndex() {
1060
+ return this.getOrAddFuncImport("env", "print_reset", [], []);
1548
1061
  }
1549
1062
 
1550
1063
  getLogImportIndex(wType, isLast = false, isBool = false) {
@@ -1557,6 +1070,8 @@ export class ModuleEmitter {
1557
1070
  return this.getOrAddFuncImport("env", `${prefix}_i32`, ["i32"], []);
1558
1071
  case "i64":
1559
1072
  return this.getOrAddFuncImport("env", `${prefix}_i64`, ["i64"], []);
1073
+ case "u64":
1074
+ return this.getOrAddFuncImport("env", `${prefix}_u64`, ["i64"], []);
1560
1075
  case "f32":
1561
1076
  return this.getOrAddFuncImport("env", `${prefix}_f32`, ["f32"], []);
1562
1077
  case "f64":
@@ -1656,123 +1171,6 @@ export class ModuleEmitter {
1656
1171
  return this.getOrAddFuncImport("env", "str_hash", ["externref"], ["i32"]);
1657
1172
  }
1658
1173
 
1659
- getStringToUpperImportIndex() {
1660
- return this.getOrAddFuncImport(
1661
- "env",
1662
- "str_to_upper",
1663
- ["externref"],
1664
- ["externref"],
1665
- );
1666
- }
1667
-
1668
- getStringToLowerImportIndex() {
1669
- return this.getOrAddFuncImport(
1670
- "env",
1671
- "str_to_lower",
1672
- ["externref"],
1673
- ["externref"],
1674
- );
1675
- }
1676
-
1677
- getStringTrimSpaceImportIndex() {
1678
- return this.getOrAddFuncImport(
1679
- "env",
1680
- "str_trim_space",
1681
- ["externref"],
1682
- ["externref"],
1683
- );
1684
- }
1685
-
1686
- getStringContainsImportIndex() {
1687
- return this.getOrAddFuncImport(
1688
- "env",
1689
- "str_contains",
1690
- ["externref", "externref"],
1691
- ["i32"],
1692
- );
1693
- }
1694
-
1695
- getStringHasPrefixImportIndex() {
1696
- return this.getOrAddFuncImport(
1697
- "env",
1698
- "str_has_prefix",
1699
- ["externref", "externref"],
1700
- ["i32"],
1701
- );
1702
- }
1703
-
1704
- getStringHasSuffixImportIndex() {
1705
- return this.getOrAddFuncImport(
1706
- "env",
1707
- "str_has_suffix",
1708
- ["externref", "externref"],
1709
- ["i32"],
1710
- );
1711
- }
1712
-
1713
- getStringIndexImportIndex() {
1714
- return this.getOrAddFuncImport(
1715
- "env",
1716
- "str_index",
1717
- ["externref", "externref"],
1718
- ["i32"],
1719
- );
1720
- }
1721
-
1722
- getStringLastIndexImportIndex() {
1723
- return this.getOrAddFuncImport(
1724
- "env",
1725
- "str_last_index",
1726
- ["externref", "externref"],
1727
- ["i32"],
1728
- );
1729
- }
1730
-
1731
- getStringRepeatImportIndex() {
1732
- return this.getOrAddFuncImport(
1733
- "env",
1734
- "str_repeat",
1735
- ["externref", "i32"],
1736
- ["externref"],
1737
- );
1738
- }
1739
-
1740
- getStringReplaceAllImportIndex() {
1741
- return this.getOrAddFuncImport(
1742
- "env",
1743
- "str_replace_all",
1744
- ["externref", "externref", "externref"],
1745
- ["externref"],
1746
- );
1747
- }
1748
-
1749
- getStringEqualFoldImportIndex() {
1750
- return this.getOrAddFuncImport(
1751
- "env",
1752
- "str_equal_fold",
1753
- ["externref", "externref"],
1754
- ["i32"],
1755
- );
1756
- }
1757
-
1758
- getStringCountImportIndex() {
1759
- return this.getOrAddFuncImport(
1760
- "env",
1761
- "str_count",
1762
- ["externref", "externref"],
1763
- ["i32"],
1764
- );
1765
- }
1766
-
1767
- getStringToValidUTF8ImportIndex() {
1768
- return this.getOrAddFuncImport(
1769
- "env",
1770
- "str_to_valid_utf8",
1771
- ["externref", "externref"],
1772
- ["externref"],
1773
- );
1774
- }
1775
-
1776
1174
  getStrFromI64ImportIndex() {
1777
1175
  return this.getOrAddFuncImport(
1778
1176
  "env",
@@ -1839,35 +1237,6 @@ export class ModuleEmitter {
1839
1237
  return this.getOrAddFuncImport("Math", "random", [], ["f64"]);
1840
1238
  }
1841
1239
 
1842
- // Imports from the STDLIB_IMPORTS table (strings/strconv/utf8/fmt/testing.Run).
1843
- getStdlibImportIndex(name) {
1844
- const idx = this.importCache.get(`env.${name}`);
1845
- if (idx === undefined) throw new Error(`Unknown runtime import: ${name}`);
1846
- return idx;
1847
- }
1848
-
1849
- getTimezoneOffsetImportIndex() {
1850
- return this.getStdlibImportIndex("time_timezone_offset");
1851
- }
1852
-
1853
- // Closure type of `func(*testing.T)` (the t.Run body).
1854
- getTestingRunClosureType() {
1855
- return this.getClosureType({
1856
- kind: "func",
1857
- params: [{ kind: "pointer", base: { kind: "named", name: "testing.T" } }],
1858
- returns: [],
1859
- });
1860
- }
1861
-
1862
- // Closure type of `func()` (the t.Cleanup body).
1863
- getTestingCleanupClosureType() {
1864
- return this.getClosureType({
1865
- kind: "func",
1866
- params: [],
1867
- returns: [],
1868
- });
1869
- }
1870
-
1871
1240
  resolveFuncIndex(name) {
1872
1241
  return this.funcMap.get(name) ?? null;
1873
1242
  }
@@ -1963,13 +1332,14 @@ export class ModuleEmitter {
1963
1332
  // Promoted methods on sName
1964
1333
  if (sInfo.embeds && sInfo.embeds.length > 0) {
1965
1334
  for (const embed of sInfo.embeds) {
1966
- const embedMethodName = `${embed.name}.${methodName}`;
1335
+ const embedType = embed.typeName ?? embed.name;
1336
+ const embedMethodName = `${embedType}.${methodName}`;
1967
1337
  if (this.funcMap.has(embedMethodName)) {
1968
1338
  const fIdx = this.resolveFuncIndex(embedMethodName);
1969
1339
  const paramGoTypes = this.getFuncParamGoTypes(embedMethodName);
1970
1340
  const paramWTypes = this.getFuncParamTypes(embedMethodName);
1971
1341
  const isPtrRecv = paramGoTypes[0]?.kind === "pointer";
1972
- const embedSInfo = this.getStructType(embed.name);
1342
+ const embedSInfo = this.getStructType(embedType);
1973
1343
 
1974
1344
  const ptrKey = `ptr:${sName}`;
1975
1345
  if (!seenKeys.has(ptrKey)) {
@@ -2180,7 +1550,12 @@ export class ModuleEmitter {
2180
1550
  if (this.checker?.implements?.(ptrType, ifaceResolved)) {
2181
1551
  if (!seen.has(sInfo.typeIndex)) {
2182
1552
  seen.add(sInfo.typeIndex);
2183
- candidates.push({ name: `*${sName}`, typeIndex: sInfo.typeIndex });
1553
+ // A typed nil `*S` is a marker object, which also satisfies it.
1554
+ candidates.push({
1555
+ name: `*${sName}`,
1556
+ typeIndex: sInfo.typeIndex,
1557
+ nilTypeIndex: this.getNilBoxType(ptrType).typeIndex,
1558
+ });
2184
1559
  }
2185
1560
  }
2186
1561