gofront 1.8.0 → 1.9.1
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.
- package/README.md +3 -3
- package/package.json +6 -5
- package/src/backend/js/expressions.js +1157 -408
- package/src/backend/js/index.js +327 -153
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +559 -2552
- package/src/backend/js/statements.js +670 -158
- package/src/backend/js/stdlib/index.js +45 -93
- package/src/backend/js/templ.js +32 -45
- package/src/backend/js/type-info.js +298 -19
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +91 -170
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +490 -965
- package/src/backend/wasm/emit-builtins.js +884 -256
- package/src/backend/wasm/emit-exprs.js +185 -77
- package/src/backend/wasm/emit-maps.js +17 -367
- package/src/backend/wasm/emit-shared.js +4 -1
- package/src/backend/wasm/emit-stmts.js +524 -240
- package/src/backend/wasm/emit.js +176 -38
- package/src/backend/wasm/globals.js +48 -8
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +44 -530
- package/src/backend/wasm/method-expr.js +12 -1
- package/src/backend/wasm/module-emitter.js +299 -770
- package/src/backend/wasm/monomorph.js +139 -8
- package/src/backend/wasm/natives.js +600 -0
- package/src/backend/wasm/prescan.js +5 -153
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -32
- package/src/backend/wasm/types.js +97 -20
- package/src/backend/wasm/variadic.js +9 -4
- package/src/cli/cli-core.js +5 -1
- package/src/cli/test-runner.js +115 -342
- package/src/compiler.js +113 -130
- package/src/lexer/lexer.js +106 -11
- package/src/lexer/templ-lexer.js +61 -18
- package/src/lexer/tokens.js +1 -0
- package/src/link/stdlib.js +355 -132
- package/src/link/type-names.js +204 -0
- package/src/link/wasm.js +30 -6
- package/src/lower/bounds.js +153 -0
- package/src/lower/captures.js +92 -33
- package/src/lower/embedding.js +62 -5
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +929 -0
- package/src/lower/functions.js +225 -7
- package/src/lower/gen-types.js +293 -0
- package/src/lower/index.js +14 -2
- package/src/lower/json-codecs.js +334 -245
- package/src/lower/ownership.js +25 -7
- package/src/lower/reachability.js +69 -51
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +30 -5
- package/src/parser/expressions.js +111 -57
- package/src/parser/statements.js +108 -0
- package/src/parser/templ.js +44 -5
- package/src/parser/types.js +12 -0
- package/src/resolver.js +1 -2
- package/src/typechecker/assignability.js +214 -19
- package/src/typechecker/const-fold.js +70 -27
- package/src/typechecker/constants.js +156 -8
- package/src/typechecker/expressions.js +490 -108
- package/src/typechecker/index.js +346 -42
- package/src/typechecker/init-order.js +136 -40
- package/src/typechecker/operand-text.js +41 -0
- package/src/typechecker/resolve.js +490 -65
- package/src/typechecker/statements.js +288 -27
- package/src/typechecker/stdlib/excluded.js +9 -5
- package/src/typechecker/stdlib/index.js +25 -9
- package/src/typechecker/termination.js +10 -1
- package/src/typechecker/types.js +287 -575
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +171 -38
- package/stdlib/internal/jsonrt/enc.go +186 -36
- package/stdlib/internal/jsonrt/scanner.go +17 -8
- package/stdlib/io/io.go +157 -1
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +16 -14
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +391 -452
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +235 -50
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +141 -3
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/fmt-runtime.js +0 -573
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -119
- package/src/backend/js/stdlib/builder.js +0 -98
- package/src/backend/js/stdlib/bytes.js +0 -368
- package/src/backend/js/stdlib/errors.js +0 -45
- package/src/backend/js/stdlib/fmt.js +0 -517
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -1167
- package/src/backend/js/stdlib/maps.js +0 -37
- package/src/backend/js/stdlib/math.js +0 -85
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -34
- package/src/backend/js/stdlib/slices.js +0 -107
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -79
- package/src/backend/js/stdlib/strings.js +0 -301
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -41
- package/src/backend/js/stdlib/time.js +0 -152
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/stdlib/bytes.js +0 -6716
- package/src/backend/wasm/stdlib/core.js +0 -10278
- package/src/backend/wasm/stdlib/io.js +0 -3578
- package/src/backend/wasm/stdlib/packages.js +0 -2402
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -2229
- package/src/typechecker/stdlib/core.js +0 -1079
- package/src/typechecker/stdlib/extended.js +0 -1210
- package/stdlib/bytes/iter.go +0 -192
- package/stdlib/bytes/search.go +0 -240
- package/stdlib/bytes/split.go +0 -218
- package/stdlib/errors/overlay.go +0 -12
- package/stdlib/maps/iter.go +0 -65
- package/stdlib/slices/extra.go +0 -73
- package/stdlib/slices/iter.go +0 -113
- package/stdlib/strings/extra.go +0 -35
- package/stdlib/strings/iter.go +0 -122
- package/stdlib/sync/extra.go +0 -105
- 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
|
|
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:
|
|
529
|
-
{ type: elemWType, mutable:
|
|
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,61 @@ 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 root = this.getTaggedSliceRoot(base);
|
|
580
|
+
const tagIndex = this.taggedSliceTypes.size + 1;
|
|
581
|
+
const tagTypeIndex = this._getTotalTypeCount();
|
|
582
|
+
this._pushType({
|
|
583
|
+
form: "struct",
|
|
584
|
+
fields: Array.from({ length: tagIndex }, () => ({
|
|
585
|
+
type: "i32",
|
|
586
|
+
mutable: false,
|
|
587
|
+
})),
|
|
588
|
+
});
|
|
589
|
+
const typeIndex = this._getTotalTypeCount();
|
|
590
|
+
this._pushType({
|
|
591
|
+
form: "struct",
|
|
592
|
+
sub: true,
|
|
593
|
+
superTypeIndex: root.typeIndex,
|
|
594
|
+
fields: [
|
|
595
|
+
...base.typeEntry.fields,
|
|
596
|
+
{
|
|
597
|
+
type: { kind: "ref", nullable: true, typeIndex: tagTypeIndex },
|
|
598
|
+
mutable: false,
|
|
599
|
+
},
|
|
600
|
+
],
|
|
601
|
+
});
|
|
602
|
+
const info = { key, typeIndex, tagTypeIndex, base, goType: sliceGoType };
|
|
603
|
+
this.taggedSliceTypes.set(key, info);
|
|
604
|
+
return info;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// The common supertype of every tagged subtype of the slice type `base`. An
|
|
608
|
+
// unnamed `[]int` in an interface is the bare slice type, which every
|
|
609
|
+
// tagged subtype (`type S []int`) also passes `ref.test` for; testing
|
|
610
|
+
// "base and not root" is what keeps `any(S{}).([]int)` from matching.
|
|
611
|
+
getTaggedSliceRoot(base) {
|
|
612
|
+
if (base.tagRoot) return base.tagRoot;
|
|
613
|
+
const typeIndex = this._getTotalTypeCount();
|
|
614
|
+
this._pushType({
|
|
615
|
+
form: "struct",
|
|
616
|
+
sub: true,
|
|
617
|
+
superTypeIndex: base.typeIndex,
|
|
618
|
+
fields: [...base.typeEntry.fields],
|
|
619
|
+
});
|
|
620
|
+
base.tagRoot = { typeIndex };
|
|
621
|
+
return base.tagRoot;
|
|
622
|
+
}
|
|
623
|
+
|
|
753
624
|
getSliceTypeByIndex(typeIndex) {
|
|
754
625
|
return this.sliceTypesByIndex?.get(typeIndex) ?? null;
|
|
755
626
|
}
|
|
@@ -848,17 +719,12 @@ export class ModuleEmitter {
|
|
|
848
719
|
clearFuncName: `__map_clear_${suffix}`,
|
|
849
720
|
keysFuncName: `__map_keys_${suffix}`,
|
|
850
721
|
valuesFuncName: `__map_values_${suffix}`,
|
|
851
|
-
cloneFuncName: `__map_clone_${suffix}`,
|
|
852
722
|
};
|
|
853
723
|
this.mapTypes.set(key, mapInfo);
|
|
854
724
|
this.mapTypesByIndex.set(mapTypeIndex, mapInfo);
|
|
855
725
|
return mapInfo;
|
|
856
726
|
}
|
|
857
727
|
|
|
858
|
-
getMapTypeByIndex(typeIndex) {
|
|
859
|
-
return this.mapTypesByIndex?.get(typeIndex) ?? null;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
728
|
getClosureType(goType) {
|
|
863
729
|
const sig = getFuncSignature(goType, this.checker);
|
|
864
730
|
const paramWTypes = sig.params
|
|
@@ -971,19 +837,6 @@ export class ModuleEmitter {
|
|
|
971
837
|
this.getStringFromCodePointImportIndex(); // env.str_from_code_point
|
|
972
838
|
this.getStringCodePointAtImportIndex(); // env.str_code_point_at
|
|
973
839
|
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
840
|
this.getStrFromI64ImportIndex();
|
|
988
841
|
this.getStrFromI32ImportIndex();
|
|
989
842
|
this.getStrFromF64ImportIndex();
|
|
@@ -993,35 +846,6 @@ export class ModuleEmitter {
|
|
|
993
846
|
this.getBytesToStrInitImportIndex();
|
|
994
847
|
this.getBytesToStrPushImportIndex();
|
|
995
848
|
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
849
|
|
|
1026
850
|
// Logging built-ins
|
|
1027
851
|
this.getPrintlnEmptyIndex(); // env.println_empty
|
|
@@ -1032,30 +856,6 @@ export class ModuleEmitter {
|
|
|
1032
856
|
}
|
|
1033
857
|
this.getLogImportIndex("i32", false, true); // env.print_bool
|
|
1034
858
|
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
859
|
}
|
|
1060
860
|
|
|
1061
861
|
_initPanicTag() {
|
|
@@ -1137,93 +937,6 @@ export class ModuleEmitter {
|
|
|
1137
937
|
return gIdx;
|
|
1138
938
|
}
|
|
1139
939
|
|
|
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
940
|
getDeferNodeTypeIndex() {
|
|
1228
941
|
if (this.deferNodeTypeIndex !== undefined) {
|
|
1229
942
|
return this.deferNodeTypeIndex;
|
|
@@ -1361,190 +1074,8 @@ export class ModuleEmitter {
|
|
|
1361
1074
|
return this.getOrAddFuncImport("env", "println_empty", [], []);
|
|
1362
1075
|
}
|
|
1363
1076
|
|
|
1364
|
-
|
|
1365
|
-
return this.getOrAddFuncImport("env", "
|
|
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
|
-
);
|
|
1077
|
+
getPrintResetIndex() {
|
|
1078
|
+
return this.getOrAddFuncImport("env", "print_reset", [], []);
|
|
1548
1079
|
}
|
|
1549
1080
|
|
|
1550
1081
|
getLogImportIndex(wType, isLast = false, isBool = false) {
|
|
@@ -1557,6 +1088,8 @@ export class ModuleEmitter {
|
|
|
1557
1088
|
return this.getOrAddFuncImport("env", `${prefix}_i32`, ["i32"], []);
|
|
1558
1089
|
case "i64":
|
|
1559
1090
|
return this.getOrAddFuncImport("env", `${prefix}_i64`, ["i64"], []);
|
|
1091
|
+
case "u64":
|
|
1092
|
+
return this.getOrAddFuncImport("env", `${prefix}_u64`, ["i64"], []);
|
|
1560
1093
|
case "f32":
|
|
1561
1094
|
return this.getOrAddFuncImport("env", `${prefix}_f32`, ["f32"], []);
|
|
1562
1095
|
case "f64":
|
|
@@ -1656,123 +1189,6 @@ export class ModuleEmitter {
|
|
|
1656
1189
|
return this.getOrAddFuncImport("env", "str_hash", ["externref"], ["i32"]);
|
|
1657
1190
|
}
|
|
1658
1191
|
|
|
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
1192
|
getStrFromI64ImportIndex() {
|
|
1777
1193
|
return this.getOrAddFuncImport(
|
|
1778
1194
|
"env",
|
|
@@ -1839,35 +1255,6 @@ export class ModuleEmitter {
|
|
|
1839
1255
|
return this.getOrAddFuncImport("Math", "random", [], ["f64"]);
|
|
1840
1256
|
}
|
|
1841
1257
|
|
|
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
1258
|
resolveFuncIndex(name) {
|
|
1872
1259
|
return this.funcMap.get(name) ?? null;
|
|
1873
1260
|
}
|
|
@@ -1961,60 +1348,60 @@ export class ModuleEmitter {
|
|
|
1961
1348
|
}
|
|
1962
1349
|
|
|
1963
1350
|
// Promoted methods on sName
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1351
|
+
const promoted = this._findPromotedMethod(sInfo, methodName);
|
|
1352
|
+
if (promoted?.iface) {
|
|
1353
|
+
this._addIfaceEmbedCandidates(
|
|
1354
|
+
candidates,
|
|
1355
|
+
seenKeys,
|
|
1356
|
+
sName,
|
|
1357
|
+
sInfo,
|
|
1358
|
+
promoted.embedPath,
|
|
1359
|
+
);
|
|
1360
|
+
} else if (promoted) {
|
|
1361
|
+
const { embedType, embedPath, viaPointer } = promoted;
|
|
1362
|
+
const embedMethodName = `${embedType}.${methodName}`;
|
|
1363
|
+
const fIdx = this.resolveFuncIndex(embedMethodName);
|
|
1364
|
+
const paramGoTypes = this.getFuncParamGoTypes(embedMethodName);
|
|
1365
|
+
const paramWTypes = this.getFuncParamTypes(embedMethodName);
|
|
1366
|
+
const isPtrRecv = paramGoTypes[0]?.kind === "pointer";
|
|
1367
|
+
const embedSInfo = this.getStructType(embedType);
|
|
1368
|
+
|
|
1369
|
+
const ptrKey = `ptr:${sName}`;
|
|
1370
|
+
if (!seenKeys.has(ptrKey)) {
|
|
1371
|
+
seenKeys.add(ptrKey);
|
|
1372
|
+
candidates.push({
|
|
1373
|
+
recvTypeName: sName,
|
|
1374
|
+
testTypeIndex: sInfo.typeIndex,
|
|
1375
|
+
isBoxedValue: false,
|
|
1376
|
+
needsValueDeref: !isPtrRecv,
|
|
1377
|
+
embedPath,
|
|
1378
|
+
nilCheckLast: !isPtrRecv,
|
|
1379
|
+
funcIndex: fIdx,
|
|
1380
|
+
targetParamTypes: paramWTypes,
|
|
1381
|
+
targetRecvWType: paramWTypes[0],
|
|
1382
|
+
structInfo: embedSInfo,
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1994
1385
|
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
structInfo: embedSInfo,
|
|
2015
|
-
});
|
|
2016
|
-
}
|
|
2017
|
-
}
|
|
1386
|
+
// A pointer-receiver method is in the value's method set only
|
|
1387
|
+
// when it is reached through an embedded pointer.
|
|
1388
|
+
if (!isPtrRecv || viaPointer) {
|
|
1389
|
+
const box = this.getIfaceBoxType({ kind: "named", name: sName });
|
|
1390
|
+
const valKey = `val:${sName}`;
|
|
1391
|
+
if (box && !seenKeys.has(valKey)) {
|
|
1392
|
+
seenKeys.add(valKey);
|
|
1393
|
+
candidates.push({
|
|
1394
|
+
recvTypeName: sName,
|
|
1395
|
+
testTypeIndex: box.typeIndex,
|
|
1396
|
+
isBoxedValue: true,
|
|
1397
|
+
needsValueDeref: false,
|
|
1398
|
+
embedPath,
|
|
1399
|
+
nilCheckLast: !isPtrRecv,
|
|
1400
|
+
funcIndex: fIdx,
|
|
1401
|
+
targetParamTypes: paramWTypes,
|
|
1402
|
+
targetRecvWType: paramWTypes[0],
|
|
1403
|
+
structInfo: embedSInfo,
|
|
1404
|
+
});
|
|
2018
1405
|
}
|
|
2019
1406
|
}
|
|
2020
1407
|
}
|
|
@@ -2125,6 +1512,116 @@ export class ModuleEmitter {
|
|
|
2125
1512
|
return candidates;
|
|
2126
1513
|
}
|
|
2127
1514
|
|
|
1515
|
+
// Whether `goType`, the type of an embedded field, is an interface whose
|
|
1516
|
+
// method set has `methodName`.
|
|
1517
|
+
embeddedInterfaceHas(goType, methodName) {
|
|
1518
|
+
let t = goType;
|
|
1519
|
+
for (let i = 0; i < 8 && t; i++) {
|
|
1520
|
+
if (t.kind === "TypeName" || t.kind === "Ident") {
|
|
1521
|
+
const named = this.checker?.types?.get(t.name);
|
|
1522
|
+
if (!named) return t.name === "error" && methodName === "Error";
|
|
1523
|
+
t = named;
|
|
1524
|
+
} else if (t.kind === "named") {
|
|
1525
|
+
t = t.underlying ?? this.checker?.types?.get(t.name)?.underlying;
|
|
1526
|
+
} else if (t.kind === "interface") {
|
|
1527
|
+
return t.methods?.has?.(methodName) ?? false;
|
|
1528
|
+
} else if (t.kind === "InterfaceType") {
|
|
1529
|
+
return (t.methods ?? []).some((m) => (m.name ?? m) === methodName);
|
|
1530
|
+
} else {
|
|
1531
|
+
return false;
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
return false;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
// Dispatch candidates for a method `sName` promotes from an embedded
|
|
1538
|
+
// interface: the embedded value is loaded and dispatched again through the
|
|
1539
|
+
// same dispatcher (`selfDispatch`).
|
|
1540
|
+
_addIfaceEmbedCandidates(candidates, seenKeys, sName, sInfo, embedPath) {
|
|
1541
|
+
const base = {
|
|
1542
|
+
recvTypeName: sName,
|
|
1543
|
+
needsValueDeref: false,
|
|
1544
|
+
embedPath,
|
|
1545
|
+
selfDispatch: true,
|
|
1546
|
+
structInfo: sInfo,
|
|
1547
|
+
};
|
|
1548
|
+
const ptrKey = `ptr:${sName}`;
|
|
1549
|
+
if (!seenKeys.has(ptrKey)) {
|
|
1550
|
+
seenKeys.add(ptrKey);
|
|
1551
|
+
candidates.push({
|
|
1552
|
+
...base,
|
|
1553
|
+
testTypeIndex: sInfo.typeIndex,
|
|
1554
|
+
isBoxedValue: false,
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
const box = this.getIfaceBoxType({ kind: "named", name: sName });
|
|
1558
|
+
const valKey = `val:${sName}`;
|
|
1559
|
+
if (box && !seenKeys.has(valKey)) {
|
|
1560
|
+
seenKeys.add(valKey);
|
|
1561
|
+
candidates.push({
|
|
1562
|
+
...base,
|
|
1563
|
+
testTypeIndex: box.typeIndex,
|
|
1564
|
+
isBoxedValue: true,
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
// The shallowest embedded type of `sInfo` (any depth) that declares
|
|
1570
|
+
// `methodName`: its name, the field path to reach it from an `sInfo`
|
|
1571
|
+
// struct, and whether that path goes through an embedded pointer. Null
|
|
1572
|
+
// when two embeds at that depth declare it (ambiguous, as in Go).
|
|
1573
|
+
_findPromotedMethod(sInfo, methodName) {
|
|
1574
|
+
let level = [{ info: sInfo, path: [], viaPointer: false }];
|
|
1575
|
+
const seen = new Set([sInfo]);
|
|
1576
|
+
while (level.length > 0) {
|
|
1577
|
+
const next = [];
|
|
1578
|
+
const hits = [];
|
|
1579
|
+
for (const { info, path, viaPointer } of level) {
|
|
1580
|
+
for (const embed of info.embeds ?? []) {
|
|
1581
|
+
const embedType = embed.typeName ?? embed.name;
|
|
1582
|
+
const goType = info.fields?.[embed.fieldIndex]?.goType;
|
|
1583
|
+
const isPtr =
|
|
1584
|
+
goType?.kind === "PointerType" || goType?.kind === "pointer";
|
|
1585
|
+
const step = {
|
|
1586
|
+
path: [
|
|
1587
|
+
...path,
|
|
1588
|
+
{
|
|
1589
|
+
parentTypeIndex: info.typeIndex,
|
|
1590
|
+
fieldIndex: embed.fieldIndex,
|
|
1591
|
+
// An embedded pointer may be nil: reading through it
|
|
1592
|
+
// is a recoverable nil dereference.
|
|
1593
|
+
...(isPtr && {
|
|
1594
|
+
ptrWType: info.fields[embed.fieldIndex].wType,
|
|
1595
|
+
}),
|
|
1596
|
+
},
|
|
1597
|
+
],
|
|
1598
|
+
viaPointer: viaPointer || isPtr,
|
|
1599
|
+
};
|
|
1600
|
+
if (this.embeddedInterfaceHas(goType, methodName)) {
|
|
1601
|
+
hits.push({ iface: true, embedPath: step.path, viaPointer: false });
|
|
1602
|
+
continue;
|
|
1603
|
+
}
|
|
1604
|
+
if (this.funcMap.has(`${embedType}.${methodName}`)) {
|
|
1605
|
+
hits.push({
|
|
1606
|
+
embedType,
|
|
1607
|
+
embedPath: step.path,
|
|
1608
|
+
viaPointer: step.viaPointer,
|
|
1609
|
+
});
|
|
1610
|
+
continue;
|
|
1611
|
+
}
|
|
1612
|
+
// A type reached twice at one depth stays twice in the next
|
|
1613
|
+
// level, so a diamond's method is ambiguous there too.
|
|
1614
|
+
const inner = this.structTypes.get(embedType);
|
|
1615
|
+
if (inner && !seen.has(inner)) next.push({ info: inner, ...step });
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
if (hits.length > 0) return hits.length === 1 ? hits[0] : null;
|
|
1619
|
+
for (const n of next) seen.add(n.info);
|
|
1620
|
+
level = next;
|
|
1621
|
+
}
|
|
1622
|
+
return null;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
2128
1625
|
// A value-receiver method of a named scalar is also in the method set of
|
|
2129
1626
|
// the pointer: `var g Getter = &x` holds a pointer box whose target is read
|
|
2130
1627
|
// before the call.
|
|
@@ -2180,12 +1677,17 @@ export class ModuleEmitter {
|
|
|
2180
1677
|
if (this.checker?.implements?.(ptrType, ifaceResolved)) {
|
|
2181
1678
|
if (!seen.has(sInfo.typeIndex)) {
|
|
2182
1679
|
seen.add(sInfo.typeIndex);
|
|
2183
|
-
|
|
1680
|
+
// A typed nil `*S` is a marker object, which also satisfies it.
|
|
1681
|
+
candidates.push({
|
|
1682
|
+
name: `*${sName}`,
|
|
1683
|
+
typeIndex: sInfo.typeIndex,
|
|
1684
|
+
nilTypeIndex: this.getNilBoxType(ptrType).typeIndex,
|
|
1685
|
+
});
|
|
2184
1686
|
}
|
|
2185
1687
|
}
|
|
2186
1688
|
|
|
2187
1689
|
// Check struct value (boxed)
|
|
2188
|
-
if (this.
|
|
1690
|
+
if (this._valueImplements(namedType, ifaceResolved)) {
|
|
2189
1691
|
const box = this.getIfaceBoxType(namedType);
|
|
2190
1692
|
if (box && !seen.has(box.typeIndex)) {
|
|
2191
1693
|
seen.add(box.typeIndex);
|
|
@@ -2203,7 +1705,7 @@ export class ModuleEmitter {
|
|
|
2203
1705
|
tVal.underlying?.kind !== "interface"
|
|
2204
1706
|
) {
|
|
2205
1707
|
if (this.checker?.implements?.(tVal, ifaceResolved)) {
|
|
2206
|
-
const box = this.
|
|
1708
|
+
const box = this._namedValueBox(tVal);
|
|
2207
1709
|
if (box && !seen.has(box.typeIndex)) {
|
|
2208
1710
|
seen.add(box.typeIndex);
|
|
2209
1711
|
candidates.push({ name: tName, typeIndex: box.typeIndex });
|
|
@@ -2223,6 +1725,33 @@ export class ModuleEmitter {
|
|
|
2223
1725
|
return candidates;
|
|
2224
1726
|
}
|
|
2225
1727
|
|
|
1728
|
+
// The WebAssembly type a value of the named non-struct type `tVal` takes
|
|
1729
|
+
// inside an interface: a defined slice type is a tagged slice (see
|
|
1730
|
+
// getTaggedSliceType), anything else an interface box.
|
|
1731
|
+
_namedValueBox(tVal) {
|
|
1732
|
+
if (!isSliceType(tVal, this.checker)) return this.getIfaceBoxType(tVal);
|
|
1733
|
+
const elem = getSliceElemType(tVal, this.checker);
|
|
1734
|
+
return elem ? this.getTaggedSliceType(tVal, elem) : null;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
// Whether the struct value `namedType` implements `iface`, including when its
|
|
1738
|
+
// pointer-receiver methods are promoted through an embedded pointer, which
|
|
1739
|
+
// puts them in the value's method set (`struct{ *Inner }`).
|
|
1740
|
+
_valueImplements(namedType, iface) {
|
|
1741
|
+
const checker = this.checker;
|
|
1742
|
+
if (checker?.implements?.(namedType, iface)) return true;
|
|
1743
|
+
const ptr = { kind: "pointer", base: namedType };
|
|
1744
|
+
if (!checker?.implements?.(ptr, iface)) return false;
|
|
1745
|
+
const st = checker.resolveType(namedType.underlying);
|
|
1746
|
+
const methods = st?.methods?.size ? st.methods : namedType.methods;
|
|
1747
|
+
const names = [...(iface.methods?.keys() ?? [])];
|
|
1748
|
+
return names.every(
|
|
1749
|
+
(n) =>
|
|
1750
|
+
!methods?.get(n)?._ptrRecv ||
|
|
1751
|
+
checker._promotedThroughPointer(namedType, n),
|
|
1752
|
+
);
|
|
1753
|
+
}
|
|
1754
|
+
|
|
2226
1755
|
// `*T` of a named scalar or slice is boxed apart from `T`.
|
|
2227
1756
|
_addPtrNamedImplementor(tVal, tName, ifaceResolved, seen, candidates) {
|
|
2228
1757
|
const ptrType = { kind: "pointer", base: tVal };
|