goscript 0.1.4 → 0.2.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 (270) hide show
  1. package/README.md +5 -2
  2. package/cmd/go_js_wasm_exec/main.go +201 -0
  3. package/cmd/go_js_wasm_exec/main_test.go +83 -0
  4. package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +7 -0
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/compiler/compile-request.go +12 -9
  8. package/compiler/compliance_test.go +0 -1
  9. package/compiler/config.go +2 -0
  10. package/compiler/gotest/request.go +28 -0
  11. package/compiler/gotest/runner.go +353 -27
  12. package/compiler/gotest/runner_test.go +273 -1
  13. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  14. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  15. package/compiler/lowered-program.go +24 -17
  16. package/compiler/lowering.go +392 -127
  17. package/compiler/lowering_bench_test.go +41 -27
  18. package/compiler/override-facts.go +15 -0
  19. package/compiler/override-parity-verifier.go +450 -0
  20. package/compiler/override-parity.go +122 -0
  21. package/compiler/override-registry_test.go +559 -0
  22. package/compiler/protobuf-ts-binding.go +514 -0
  23. package/compiler/protobuf-ts-binding_test.go +172 -0
  24. package/compiler/semantic-model-types.go +9 -4
  25. package/compiler/semantic-model.go +282 -70
  26. package/compiler/semantic-model_test.go +82 -1
  27. package/compiler/service.go +20 -1
  28. package/compiler/skeleton_test.go +62 -8
  29. package/compiler/typescript-emitter.go +128 -13
  30. package/dist/gs/builtin/slice.d.ts +2 -1
  31. package/dist/gs/builtin/slice.js +29 -4
  32. package/dist/gs/builtin/slice.js.map +1 -1
  33. package/dist/gs/builtin/type.d.ts +13 -5
  34. package/dist/gs/builtin/type.js +153 -60
  35. package/dist/gs/builtin/type.js.map +1 -1
  36. package/dist/gs/builtin/varRef.d.ts +11 -0
  37. package/dist/gs/builtin/varRef.js +57 -2
  38. package/dist/gs/builtin/varRef.js.map +1 -1
  39. package/dist/gs/bytes/buffer.gs.js +1 -1
  40. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  41. package/dist/gs/bytes/reader.gs.js +1 -1
  42. package/dist/gs/bytes/reader.gs.js.map +1 -1
  43. package/dist/gs/compress/zlib/index.d.ts +10 -3
  44. package/dist/gs/compress/zlib/index.js +50 -16
  45. package/dist/gs/compress/zlib/index.js.map +1 -1
  46. package/dist/gs/encoding/json/index.d.ts +114 -0
  47. package/dist/gs/encoding/json/index.js +544 -36
  48. package/dist/gs/encoding/json/index.js.map +1 -1
  49. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
  50. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
  51. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  52. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  53. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  54. package/dist/gs/go/scanner/index.d.ts +2 -0
  55. package/dist/gs/go/scanner/index.js +29 -5
  56. package/dist/gs/go/scanner/index.js.map +1 -1
  57. package/dist/gs/go/token/index.js +22 -6
  58. package/dist/gs/go/token/index.js.map +1 -1
  59. package/dist/gs/hash/index.d.ts +6 -0
  60. package/dist/gs/hash/index.js +20 -0
  61. package/dist/gs/hash/index.js.map +1 -1
  62. package/dist/gs/internal/goarch/index.d.ts +43 -3
  63. package/dist/gs/internal/goarch/index.js +42 -10
  64. package/dist/gs/internal/goarch/index.js.map +1 -1
  65. package/dist/gs/io/fs/fs.js +26 -14
  66. package/dist/gs/io/fs/fs.js.map +1 -1
  67. package/dist/gs/io/fs/readdir.js +4 -2
  68. package/dist/gs/io/fs/readdir.js.map +1 -1
  69. package/dist/gs/io/fs/sub.js +8 -1
  70. package/dist/gs/io/fs/sub.js.map +1 -1
  71. package/dist/gs/io/io.d.ts +2 -0
  72. package/dist/gs/io/io.js.map +1 -1
  73. package/dist/gs/math/bits/index.d.ts +5 -0
  74. package/dist/gs/math/bits/index.js +16 -4
  75. package/dist/gs/math/bits/index.js.map +1 -1
  76. package/dist/gs/mime/index.d.ts +16 -0
  77. package/dist/gs/mime/index.js +315 -6
  78. package/dist/gs/mime/index.js.map +1 -1
  79. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  80. package/dist/gs/net/http/httptest/index.js +85 -6
  81. package/dist/gs/net/http/httptest/index.js.map +1 -1
  82. package/dist/gs/net/http/index.d.ts +300 -5
  83. package/dist/gs/net/http/index.js +1598 -58
  84. package/dist/gs/net/http/index.js.map +1 -1
  85. package/dist/gs/os/dir_unix.gs.js +1 -1
  86. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  87. package/dist/gs/os/error.gs.js +1 -1
  88. package/dist/gs/os/error.gs.js.map +1 -1
  89. package/dist/gs/os/exec.gs.d.ts +1 -0
  90. package/dist/gs/os/exec.gs.js +4 -8
  91. package/dist/gs/os/exec.gs.js.map +1 -1
  92. package/dist/gs/os/exec_posix.gs.js +1 -1
  93. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  94. package/dist/gs/os/index.d.ts +1 -1
  95. package/dist/gs/os/index.js +1 -1
  96. package/dist/gs/os/index.js.map +1 -1
  97. package/dist/gs/os/proc.gs.d.ts +4 -0
  98. package/dist/gs/os/proc.gs.js +12 -6
  99. package/dist/gs/os/proc.gs.js.map +1 -1
  100. package/dist/gs/os/root_js.gs.js +1 -1
  101. package/dist/gs/os/root_js.gs.js.map +1 -1
  102. package/dist/gs/os/types.gs.js +1 -1
  103. package/dist/gs/os/types.gs.js.map +1 -1
  104. package/dist/gs/os/types_js.gs.js +1 -1
  105. package/dist/gs/os/types_js.gs.js.map +1 -1
  106. package/dist/gs/os/types_unix.gs.js +1 -1
  107. package/dist/gs/os/types_unix.gs.js.map +1 -1
  108. package/dist/gs/path/path.js +11 -7
  109. package/dist/gs/path/path.js.map +1 -1
  110. package/dist/gs/reflect/index.d.ts +5 -4
  111. package/dist/gs/reflect/index.js +4 -3
  112. package/dist/gs/reflect/index.js.map +1 -1
  113. package/dist/gs/reflect/map.js +15 -0
  114. package/dist/gs/reflect/map.js.map +1 -1
  115. package/dist/gs/reflect/type.d.ts +25 -6
  116. package/dist/gs/reflect/type.js +1418 -228
  117. package/dist/gs/reflect/type.js.map +1 -1
  118. package/dist/gs/reflect/types.d.ts +14 -6
  119. package/dist/gs/reflect/types.js +35 -1
  120. package/dist/gs/reflect/types.js.map +1 -1
  121. package/dist/gs/reflect/value.d.ts +1 -0
  122. package/dist/gs/reflect/value.js +83 -41
  123. package/dist/gs/reflect/value.js.map +1 -1
  124. package/dist/gs/reflect/visiblefields.js +4 -140
  125. package/dist/gs/reflect/visiblefields.js.map +1 -1
  126. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  127. package/dist/gs/runtime/pprof/index.js +50 -30
  128. package/dist/gs/runtime/pprof/index.js.map +1 -1
  129. package/dist/gs/runtime/runtime.js +5 -4
  130. package/dist/gs/runtime/runtime.js.map +1 -1
  131. package/dist/gs/runtime/trace/index.js +5 -19
  132. package/dist/gs/runtime/trace/index.js.map +1 -1
  133. package/dist/gs/strconv/atoi.gs.js +1 -1
  134. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  135. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  136. package/dist/gs/strconv/complex.gs.js +148 -0
  137. package/dist/gs/strconv/complex.gs.js.map +1 -0
  138. package/dist/gs/strconv/index.d.ts +1 -0
  139. package/dist/gs/strconv/index.js +1 -0
  140. package/dist/gs/strconv/index.js.map +1 -1
  141. package/dist/gs/strings/builder.js +1 -1
  142. package/dist/gs/strings/reader.js +9 -5
  143. package/dist/gs/strings/reader.js.map +1 -1
  144. package/dist/gs/strings/replace.js +15 -7
  145. package/dist/gs/strings/replace.js.map +1 -1
  146. package/dist/gs/strings/strings.d.ts +5 -0
  147. package/dist/gs/strings/strings.js +57 -5
  148. package/dist/gs/strings/strings.js.map +1 -1
  149. package/dist/gs/sync/atomic/type.gs.js +9 -9
  150. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  151. package/dist/gs/sync/atomic/value.gs.js +2 -2
  152. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  153. package/dist/gs/syscall/env.js +22 -14
  154. package/dist/gs/syscall/env.js.map +1 -1
  155. package/dist/gs/testing/testing.js +55 -13
  156. package/dist/gs/testing/testing.js.map +1 -1
  157. package/dist/gs/time/time.d.ts +24 -1
  158. package/dist/gs/time/time.js +43 -3
  159. package/dist/gs/time/time.js.map +1 -1
  160. package/dist/gs/unique/index.js +7 -1
  161. package/dist/gs/unique/index.js.map +1 -1
  162. package/go.mod +3 -3
  163. package/go.sum +16 -0
  164. package/gs/builtin/runtime-contract.test.ts +218 -21
  165. package/gs/builtin/slice.ts +44 -4
  166. package/gs/builtin/type.ts +226 -59
  167. package/gs/builtin/varRef.ts +85 -2
  168. package/gs/bytes/buffer.gs.ts +1 -1
  169. package/gs/bytes/reader.gs.ts +1 -1
  170. package/gs/compress/zlib/index.test.ts +62 -1
  171. package/gs/compress/zlib/index.ts +53 -16
  172. package/gs/compress/zlib/parity.json +51 -0
  173. package/gs/encoding/json/index.test.ts +360 -6
  174. package/gs/encoding/json/index.ts +679 -38
  175. package/gs/encoding/json/parity.json +81 -0
  176. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
  177. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
  178. package/gs/github.com/pkg/errors/errors.ts +54 -30
  179. package/gs/go/scanner/index.test.ts +39 -56
  180. package/gs/go/scanner/index.ts +33 -5
  181. package/gs/go/scanner/parity.json +27 -0
  182. package/gs/go/token/index.ts +22 -6
  183. package/gs/hash/index.test.ts +20 -33
  184. package/gs/hash/index.ts +28 -0
  185. package/gs/hash/parity.json +21 -0
  186. package/gs/internal/goarch/index.test.ts +32 -0
  187. package/gs/internal/goarch/index.ts +45 -13
  188. package/gs/internal/goarch/parity.json +144 -0
  189. package/gs/io/fs/fs.ts +26 -14
  190. package/gs/io/fs/readdir.ts +4 -4
  191. package/gs/io/fs/sub.ts +8 -1
  192. package/gs/io/io.ts +1 -0
  193. package/gs/io/parity.json +162 -0
  194. package/gs/math/bits/index.test.ts +14 -1
  195. package/gs/math/bits/index.ts +23 -4
  196. package/gs/math/bits/parity.json +156 -0
  197. package/gs/mime/index.test.ts +90 -0
  198. package/gs/mime/index.ts +369 -6
  199. package/gs/mime/parity.json +36 -0
  200. package/gs/net/http/httptest/index.test.ts +98 -2
  201. package/gs/net/http/httptest/index.ts +101 -6
  202. package/gs/net/http/httptest/parity.json +15 -0
  203. package/gs/net/http/index.test.ts +781 -12
  204. package/gs/net/http/index.ts +1860 -139
  205. package/gs/net/http/meta.json +16 -1
  206. package/gs/net/http/parity.json +193 -0
  207. package/gs/os/dir_unix.gs.ts +1 -1
  208. package/gs/os/error.gs.ts +1 -1
  209. package/gs/os/exec.gs.ts +4 -8
  210. package/gs/os/exec_posix.gs.ts +1 -1
  211. package/gs/os/index.test.ts +9 -0
  212. package/gs/os/index.ts +1 -0
  213. package/gs/os/parity.json +9 -0
  214. package/gs/os/proc.gs.ts +18 -5
  215. package/gs/os/proc.test.ts +26 -0
  216. package/gs/os/root_js.gs.ts +1 -1
  217. package/gs/os/types.gs.ts +1 -1
  218. package/gs/os/types_js.gs.ts +1 -1
  219. package/gs/os/types_unix.gs.ts +1 -1
  220. package/gs/path/path.ts +11 -7
  221. package/gs/reflect/field.test.ts +37 -15
  222. package/gs/reflect/function-types.test.ts +518 -22
  223. package/gs/reflect/index.ts +8 -6
  224. package/gs/reflect/map.ts +20 -0
  225. package/gs/reflect/meta.json +6 -4
  226. package/gs/reflect/parity.json +234 -0
  227. package/gs/reflect/sliceat.test.ts +156 -0
  228. package/gs/reflect/structof.test.ts +401 -0
  229. package/gs/reflect/type.ts +1897 -317
  230. package/gs/reflect/typefor.test.ts +510 -10
  231. package/gs/reflect/types.ts +43 -18
  232. package/gs/reflect/value.ts +105 -45
  233. package/gs/reflect/visiblefields.ts +5 -168
  234. package/gs/runtime/parity.json +24 -0
  235. package/gs/runtime/pprof/index.test.ts +29 -7
  236. package/gs/runtime/pprof/index.ts +56 -30
  237. package/gs/runtime/pprof/parity.json +27 -0
  238. package/gs/runtime/runtime.test.ts +3 -1
  239. package/gs/runtime/runtime.ts +4 -3
  240. package/gs/runtime/trace/index.test.ts +5 -3
  241. package/gs/runtime/trace/index.ts +8 -20
  242. package/gs/runtime/trace/parity.json +36 -0
  243. package/gs/strconv/atoi.gs.ts +1 -1
  244. package/gs/strconv/complex.gs.ts +174 -0
  245. package/gs/strconv/complex.test.ts +65 -0
  246. package/gs/strconv/index.ts +1 -0
  247. package/gs/strconv/parity.json +120 -0
  248. package/gs/strings/builder.ts +1 -1
  249. package/gs/strings/parity.json +186 -0
  250. package/gs/strings/reader.ts +9 -5
  251. package/gs/strings/replace.ts +15 -7
  252. package/gs/strings/strings.test.ts +22 -2
  253. package/gs/strings/strings.ts +64 -6
  254. package/gs/sync/atomic/type.gs.ts +9 -9
  255. package/gs/sync/atomic/value.gs.ts +2 -2
  256. package/gs/syscall/env.ts +29 -14
  257. package/gs/testing/testing.test.ts +67 -0
  258. package/gs/testing/testing.ts +87 -19
  259. package/gs/time/parity.json +225 -0
  260. package/gs/time/time.test.ts +20 -2
  261. package/gs/time/time.ts +49 -7
  262. package/gs/unique/index.ts +7 -1
  263. package/package.json +4 -2
  264. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  265. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -926
  266. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  267. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -38
  268. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1361
  269. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
  270. /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
@@ -9,10 +9,9 @@ export { StructField }
9
9
  import { MapIter } from './map.js'
10
10
  import {
11
11
  getTypeByName as builtinGetTypeByName,
12
- TypeKind,
13
12
  isStructTypeInfo,
14
13
  isInterfaceTypeInfo,
15
- isStructFieldInfo,
14
+ structFieldRuntimeKey,
16
15
  } from '../builtin/type.js'
17
16
  import { Zero } from './value.js'
18
17
  import { DeepEqual } from './deepequal.js'
@@ -181,8 +180,13 @@ export const UnsafePointer: Kind = 26
181
180
 
182
181
  const pointerAddressStride = 0x100000000
183
182
  const pointerAddresses = new WeakMap<object, number>()
183
+ const fieldPointerAddresses = new WeakMap<
184
+ object,
185
+ globalThis.Map<string, number>
186
+ >()
184
187
  let nextPointerAddress = 1
185
188
  const canonicalTypes = new globalThis.Map<string, Type>()
189
+ const constructingRegisteredTypes = new globalThis.Map<string, Type>()
186
190
 
187
191
  function pointerAddress(value: object): number {
188
192
  let address = pointerAddresses.get(value)
@@ -194,16 +198,139 @@ function pointerAddress(value: object): number {
194
198
  return address
195
199
  }
196
200
 
201
+ function fieldPointerAddress(target: object, key: string): number {
202
+ let addresses = fieldPointerAddresses.get(target)
203
+ if (addresses === undefined) {
204
+ addresses = new globalThis.Map<string, number>()
205
+ fieldPointerAddresses.set(target, addresses)
206
+ }
207
+ let address = addresses.get(key)
208
+ if (address === undefined) {
209
+ address = nextPointerAddress * pointerAddressStride
210
+ nextPointerAddress++
211
+ addresses.set(key, address)
212
+ }
213
+ return address
214
+ }
215
+
197
216
  function internType(t: Type): Type {
198
- const key = `${t.Kind()}:${t.PkgPath()}:${t.Name()}:${t.String()}`
217
+ const key = typeIdentityKey(t)
199
218
  const existing = canonicalTypes.get(key)
200
219
  if (existing) {
220
+ mergeTypeMetadata(existing, t)
201
221
  return existing
202
222
  }
203
223
  canonicalTypes.set(key, t)
204
224
  return t
205
225
  }
206
226
 
227
+ function mergeTypeMetadata(target: Type, source: Type): void {
228
+ if (target instanceof BasicType && source instanceof BasicType) {
229
+ target.mergeMethodSignatures(source.methodSignatures())
230
+ return
231
+ }
232
+ if (target instanceof PointerType && source instanceof PointerType) {
233
+ target.mergeMethodSignatures(source.methodSignatures())
234
+ return
235
+ }
236
+ if (target instanceof FunctionType && source instanceof FunctionType) {
237
+ target.mergeSignature(source)
238
+ target.mergeMethodSignatures(source.methodSignatures())
239
+ }
240
+ }
241
+
242
+ function typeIdentityKey(t: Type, seen = new Set<Type>()): string {
243
+ if (seen.has(t)) {
244
+ return `${t.Kind()}:${t.PkgPath()}:${t.Name()}:${t.String()}`
245
+ }
246
+ seen.add(t)
247
+ if (t instanceof StructType) {
248
+ return t.identityKey(seen)
249
+ }
250
+ switch (t.Kind()) {
251
+ case Array:
252
+ return `${t.Kind()}:${t.Len()}:${typeIdentityKey(t.Elem(), seen)}`
253
+ case Chan:
254
+ case Ptr:
255
+ case Slice:
256
+ return `${t.Kind()}:${t.String()}:${typeIdentityKey(t.Elem(), seen)}`
257
+ case Map:
258
+ return `${t.Kind()}:${typeIdentityKey(t.Key(), seen)}:${typeIdentityKey(t.Elem(), seen)}`
259
+ case Func: {
260
+ if (t.Name() !== '') {
261
+ return `${t.Kind()}:named:${t.PkgPath()}:${t.Name()}`
262
+ }
263
+ const params = globalThis.Array.from(
264
+ { length: t.NumIn() },
265
+ (_unused, idx) => typeIdentityKey(t.In(idx), seen),
266
+ )
267
+ const results = globalThis.Array.from(
268
+ { length: t.NumOut() },
269
+ (_unused, idx) => typeIdentityKey(t.Out(idx), seen),
270
+ )
271
+ return `${t.Kind()}:${t.PkgPath()}:${t.Name()}:${t.String()}:${t.IsVariadic()}:${params.join(',')}:${results.join(',')}`
272
+ }
273
+ default:
274
+ return `${t.Kind()}:${t.PkgPath()}:${t.Name()}:${t.String()}`
275
+ }
276
+ }
277
+
278
+ function typeUnderlyingIdentityKey(t: Type, seen = new Set<Type>()): string {
279
+ if (seen.has(t)) {
280
+ return `${t.Kind()}:${t.PkgPath()}:${t.Name()}:${t.String()}`
281
+ }
282
+ seen.add(t)
283
+ if (t instanceof BasicType) {
284
+ return `basic:${t.underlyingName()}`
285
+ }
286
+ if (t instanceof StructType) {
287
+ return t.underlyingIdentityKey(seen)
288
+ }
289
+ switch (t.Kind()) {
290
+ case Array:
291
+ return `array:${t.Len()}:${typeIdentityKey(t.Elem(), seen)}`
292
+ case Chan:
293
+ return `chan:${t.String()}:${typeIdentityKey(t.Elem(), seen)}`
294
+ case Ptr:
295
+ return `ptr:${typeIdentityKey(t.Elem(), seen)}`
296
+ case Slice:
297
+ return `slice:${typeIdentityKey(t.Elem(), seen)}`
298
+ case Map:
299
+ return `map:${typeIdentityKey(t.Key(), seen)}:${typeIdentityKey(
300
+ t.Elem(),
301
+ seen,
302
+ )}`
303
+ case Func: {
304
+ const params = globalThis.Array.from(
305
+ { length: t.NumIn() },
306
+ (_unused, idx) => typeIdentityKey(t.In(idx), seen),
307
+ )
308
+ const results = globalThis.Array.from(
309
+ { length: t.NumOut() },
310
+ (_unused, idx) => typeIdentityKey(t.Out(idx), seen),
311
+ )
312
+ return `func:${t.IsVariadic()}:${params.join(',')}:${results.join(',')}`
313
+ }
314
+ case Interface:
315
+ return `interface:${typeMethods(t).map(methodSignatureIdentityKey).join('|')}`
316
+ default:
317
+ return `${t.Kind()}:${t.PkgPath()}:${t.Name()}:${t.String()}`
318
+ }
319
+ }
320
+
321
+ function typeIsNamed(t: Type): boolean {
322
+ if (t.Kind() === Interface) {
323
+ return t.String() !== 'interface{}' && !t.String().startsWith('interface {')
324
+ }
325
+ if (t.Kind() === Struct || t.Kind() === Func) {
326
+ return t.Name() !== ''
327
+ }
328
+ if (t instanceof BasicType) {
329
+ return t.Kind() !== Invalid && t.Name() !== ''
330
+ }
331
+ return t.Name() !== ''
332
+ }
333
+
207
334
  // Type is the representation of a Go type.
208
335
  export interface Type {
209
336
  // String returns a string representation of the type.
@@ -222,6 +349,26 @@ export interface Type {
222
349
  // NumField returns a struct type's field count.
223
350
  NumField(): number
224
351
 
352
+ // NumIn returns a function type's input count.
353
+ // Panics if the type's Kind is not Func.
354
+ NumIn(): number
355
+
356
+ // In returns a function type's i'th input type.
357
+ // Panics if the type's Kind is not Func or i is out of range.
358
+ In(i: number): Type
359
+
360
+ // NumOut returns a function type's output count.
361
+ // Panics if the type's Kind is not Func.
362
+ NumOut(): number
363
+
364
+ // Out returns a function type's i'th output type.
365
+ // Panics if the type's Kind is not Func or i is out of range.
366
+ Out(i: number): Type
367
+
368
+ // IsVariadic reports whether a function type's final input is variadic.
369
+ // Panics if the type's Kind is not Func.
370
+ IsVariadic(): boolean
371
+
225
372
  // PkgPath returns the package path for named types, empty for unnamed types.
226
373
  PkgPath(): string
227
374
 
@@ -281,6 +428,10 @@ export interface Type {
281
428
  Comparable(): boolean
282
429
  }
283
430
 
431
+ function nonFunctionTypePanic(method: string, t: Type): never {
432
+ throw new Error(`reflect: ${method} of non-func type ${t.String()}`)
433
+ }
434
+
284
435
  // InvalidTypeInstance is a singleton type for invalid/zero reflect.Value
285
436
  class InvalidTypeClass implements Type {
286
437
  Kind(): Kind {
@@ -310,6 +461,21 @@ class InvalidTypeClass implements Type {
310
461
  NumField(): number {
311
462
  return 0
312
463
  }
464
+ NumIn(): number {
465
+ return nonFunctionTypePanic('NumIn', this)
466
+ }
467
+ In(_i: number): Type {
468
+ return nonFunctionTypePanic('In', this)
469
+ }
470
+ NumOut(): number {
471
+ return nonFunctionTypePanic('NumOut', this)
472
+ }
473
+ Out(_i: number): Type {
474
+ return nonFunctionTypePanic('Out', this)
475
+ }
476
+ IsVariadic(): boolean {
477
+ return nonFunctionTypePanic('IsVariadic', this)
478
+ }
313
479
  Field(_i: number): StructField {
314
480
  throw new Error('reflect: Field of invalid type')
315
481
  }
@@ -476,6 +642,10 @@ export class Value {
476
642
  }
477
643
 
478
644
  public Len(): number {
645
+ if (this.Kind() === Slice || this.Kind() === Array) {
646
+ return $.len(this._value as any)
647
+ }
648
+
479
649
  // Check for slice objects created by $.arrayToSlice
480
650
  if (
481
651
  this._value &&
@@ -539,8 +709,9 @@ export class Value {
539
709
  }
540
710
 
541
711
  public Index(i: number): Value {
542
- if (globalThis.Array.isArray(this._value)) {
543
- return new Value(this._value[i], getTypeOf(this._value[i]))
712
+ if (this.Kind() === Slice || this.Kind() === Array) {
713
+ const ref = $.indexRef(this._value as any, i) as $.VarRef<ReflectValue>
714
+ return new Value(ref.value, this._type.Elem(), ref)
544
715
  }
545
716
  throw new Error(
546
717
  'reflect: call of reflect.Value.Index on ' +
@@ -621,17 +792,18 @@ export class Value {
621
792
  }
622
793
 
623
794
  const field = this.Type().Field(i)
795
+ const fieldKey = structFieldStorageKey(this.Type(), i)
624
796
  if (!field) {
625
797
  throw new Error('reflect: struct field index out of range')
626
798
  }
627
799
 
628
800
  const parentObj = this._value as Record<string, any>
629
- let fieldVal = parentObj[field.Name]
801
+ let fieldVal = parentObj[fieldKey]
630
802
  if (fieldVal === undefined) {
631
803
  fieldVal = null
632
804
  }
633
805
  // Pass parent struct and field name so Set() can update the struct
634
- return new Value(fieldVal, field.Type, undefined, parentObj, field.Name)
806
+ return new Value(fieldVal, field.Type, undefined, parentObj, fieldKey)
635
807
  }
636
808
 
637
809
  public FieldByIndex(index: $.Slice<number>): Value {
@@ -670,6 +842,9 @@ export class Value {
670
842
  if (this._value === null || this._value === undefined) {
671
843
  return 0
672
844
  }
845
+ if ($.isOwnedPointerHandle(this._value)) {
846
+ return $.ownedPointerAddress(this._value)
847
+ }
673
848
  if ($.isVarRef(this._value)) {
674
849
  const address = this._value.__goAddress?.()
675
850
  if (address !== undefined) {
@@ -694,12 +869,26 @@ export class Value {
694
869
  return 0
695
870
  }
696
871
 
697
- public UnsafeAddr(): number | { value: Value } {
872
+ public UnsafeAddr(): number | $.OwnedPointerHandle<ReflectValue> {
698
873
  if (!this.CanAddr()) {
699
874
  throw new ValueError({ Kind: this.Kind(), Method: 'UnsafeAddr' })
700
875
  }
701
876
  if (this._parentStruct && this._fieldName) {
702
- return { value: this }
877
+ const target = this._parentStruct
878
+ const key = this._fieldName
879
+ const ref = $.fieldRef(
880
+ target,
881
+ key as keyof typeof target,
882
+ ) as $.VarRef<ReflectValue>
883
+ return {
884
+ __goOwnedPointer: true,
885
+ __goAddress: () => fieldPointerAddress(target, key),
886
+ __goRef: () => ref,
887
+ }
888
+ }
889
+ if (this._parentVarRef?.__goPointer) {
890
+ return this._parentVarRef
891
+ .__goPointer as $.OwnedPointerHandle<ReflectValue>
703
892
  }
704
893
  return this.Pointer()
705
894
  }
@@ -735,6 +924,9 @@ export class Value {
735
924
  if (this._parentStruct && this._fieldName) {
736
925
  return new Value($.fieldRef(this._parentStruct, this._fieldName), ptrType)
737
926
  }
927
+ if (this._parentVarRef) {
928
+ return new Value(this._parentVarRef, ptrType)
929
+ }
738
930
  return new Value($.varRef(this._value), ptrType)
739
931
  }
740
932
 
@@ -748,23 +940,9 @@ export class Value {
748
940
  if (!this.CanSet()) {
749
941
  throw new Error('reflect: assign to invalid value')
750
942
  }
751
- // Interface types can accept any value
752
- if (this.Kind() === Interface) {
753
- this._value = x.value
754
- // Also update the parent VarRef if we were dereferenced from one
755
- if (this._parentVarRef) {
756
- this._parentVarRef.value = x.value
757
- }
758
- // Also update the parent struct field if this is a struct field
759
- if (this._parentStruct && this._fieldName) {
760
- this._parentStruct[this._fieldName] = x.value
761
- }
762
- return
763
- }
764
- // For other types, check if types are compatible (simplified check)
765
943
  const thisType = this.Type()
766
944
  const xType = x.Type()
767
- if (thisType.Kind() !== xType.Kind()) {
945
+ if (!xType.AssignableTo(thisType)) {
768
946
  throw new Error('reflect: assign to wrong type')
769
947
  }
770
948
  this._value = x.value
@@ -799,22 +977,36 @@ export class Value {
799
977
  if (typeof method !== 'function') {
800
978
  return new Value()
801
979
  }
802
- return new Value(method.bind(receiver), new FunctionType('func'))
980
+ const [signature] = methodSignatureByName(this.Type(), name)
981
+ const methodType =
982
+ signature ?
983
+ methodTypeFromSignature(signature, this.Type(), false)
984
+ : new FunctionType('func')
985
+ return new Value(method.bind(receiver), methodType)
803
986
  }
804
987
 
805
- public Call(inArgs: $.Slice<Value>): $.Slice<Value> {
988
+ public async Call(inArgs: $.Slice<Value>): Promise<$.Slice<Value>> {
806
989
  if (this.Kind() !== Func || typeof this._value !== 'function') {
807
990
  throw new ValueError({ Kind: this.Kind(), Method: 'Call' })
808
991
  }
809
- const args = $.asArray(inArgs).map((arg) => arg.Interface())
810
- const result = this._value(...args) as ReflectValue | ReflectValue[]
811
- if (globalThis.Array.isArray(result)) {
812
- return $.arrayToSlice(result.map((value) => ValueOf(value)))
813
- }
814
- if (result === undefined) {
815
- return $.makeSlice<Value>(0)
992
+ return await callReflectFunction(
993
+ this._value as (...args: unknown[]) => unknown,
994
+ this._type,
995
+ inArgs,
996
+ 'Call',
997
+ )
998
+ }
999
+
1000
+ public async CallSlice(inArgs: $.Slice<Value>): Promise<$.Slice<Value>> {
1001
+ if (this.Kind() !== Func || typeof this._value !== 'function') {
1002
+ throw new ValueError({ Kind: this.Kind(), Method: 'CallSlice' })
816
1003
  }
817
- return $.arrayToSlice([ValueOf(result)])
1004
+ return await callReflectFunction(
1005
+ this._value as (...args: unknown[]) => unknown,
1006
+ this._type,
1007
+ inArgs,
1008
+ 'CallSlice',
1009
+ )
818
1010
  }
819
1011
 
820
1012
  public IsZero(): boolean {
@@ -1149,10 +1341,7 @@ export class Value {
1149
1341
  public Cap(): number {
1150
1342
  const k = this.Kind()
1151
1343
  if (k === Slice || k === Array) {
1152
- if (globalThis.Array.isArray(this._value)) {
1153
- return this._value.length
1154
- }
1155
- return 0
1344
+ return $.cap(this._value as any)
1156
1345
  }
1157
1346
  if (k === Chan) {
1158
1347
  return 0 // Simplified
@@ -1242,6 +1431,7 @@ export class BasicType implements Type {
1242
1431
  private _name: string,
1243
1432
  private _size: number = 8,
1244
1433
  private _typeName: string = '',
1434
+ private _methods: $.MethodSignature[] = [],
1245
1435
  ) {}
1246
1436
 
1247
1437
  public String(): string {
@@ -1252,6 +1442,10 @@ export class BasicType implements Type {
1252
1442
  return this._kind
1253
1443
  }
1254
1444
 
1445
+ public underlyingName(): string {
1446
+ return Kind_String(this._kind)
1447
+ }
1448
+
1255
1449
  public Comparable(): boolean {
1256
1450
  return this._kind !== Func && this._kind !== Map && this._kind !== Slice
1257
1451
  }
@@ -1268,6 +1462,26 @@ export class BasicType implements Type {
1268
1462
  return 0
1269
1463
  }
1270
1464
 
1465
+ public NumIn(): number {
1466
+ return nonFunctionTypePanic('NumIn', this)
1467
+ }
1468
+
1469
+ public In(_i: number): Type {
1470
+ return nonFunctionTypePanic('In', this)
1471
+ }
1472
+
1473
+ public NumOut(): number {
1474
+ return nonFunctionTypePanic('NumOut', this)
1475
+ }
1476
+
1477
+ public Out(_i: number): Type {
1478
+ return nonFunctionTypePanic('Out', this)
1479
+ }
1480
+
1481
+ public IsVariadic(): boolean {
1482
+ return nonFunctionTypePanic('IsVariadic', this)
1483
+ }
1484
+
1271
1485
  public PkgPath(): string {
1272
1486
  if (this._typeName) {
1273
1487
  const dotIndex = this._typeName.lastIndexOf('.')
@@ -1315,7 +1529,7 @@ export class BasicType implements Type {
1315
1529
  if (u.Kind() !== Interface) {
1316
1530
  throw new Error('reflect: non-interface type passed to Type.Implements')
1317
1531
  }
1318
- return false
1532
+ return typeImplementsInterface(this, u)
1319
1533
  }
1320
1534
 
1321
1535
  public AssignableTo(u: Type | null): boolean {
@@ -1386,10 +1600,18 @@ export class BasicType implements Type {
1386
1600
  }
1387
1601
 
1388
1602
  public NumMethod(): number {
1389
- return 0
1603
+ return typeMethods(this).length
1390
1604
  }
1391
- public MethodByName(_name: string): [Method, boolean] {
1392
- return [zeroMethod(), false]
1605
+ public MethodByName(name: string): [Method, boolean] {
1606
+ return typeMethodByName(this, name)
1607
+ }
1608
+
1609
+ public methodSignatures(): $.MethodSignature[] {
1610
+ return this._methods
1611
+ }
1612
+
1613
+ public mergeMethodSignatures(methods: $.MethodSignature[]): void {
1614
+ this._methods = mergeMethodSignatureList(this._methods, methods)
1393
1615
  }
1394
1616
 
1395
1617
  public Len(): number {
@@ -1463,6 +1685,26 @@ class SliceType implements Type {
1463
1685
  return 0
1464
1686
  }
1465
1687
 
1688
+ public NumIn(): number {
1689
+ return nonFunctionTypePanic('NumIn', this)
1690
+ }
1691
+
1692
+ public In(_i: number): Type {
1693
+ return nonFunctionTypePanic('In', this)
1694
+ }
1695
+
1696
+ public NumOut(): number {
1697
+ return nonFunctionTypePanic('NumOut', this)
1698
+ }
1699
+
1700
+ public Out(_i: number): Type {
1701
+ return nonFunctionTypePanic('Out', this)
1702
+ }
1703
+
1704
+ public IsVariadic(): boolean {
1705
+ return nonFunctionTypePanic('IsVariadic', this)
1706
+ }
1707
+
1466
1708
  public PkgPath(): string {
1467
1709
  return ''
1468
1710
  }
@@ -1497,7 +1739,7 @@ class SliceType implements Type {
1497
1739
  if (u.Kind() !== Interface) {
1498
1740
  throw new Error('reflect: non-interface type passed to Type.Implements')
1499
1741
  }
1500
- return false
1742
+ return typeImplementsInterface(this, u)
1501
1743
  }
1502
1744
 
1503
1745
  public AssignableTo(u: Type | null): boolean {
@@ -1563,6 +1805,26 @@ class ArrayType implements Type {
1563
1805
  return 0
1564
1806
  }
1565
1807
 
1808
+ public NumIn(): number {
1809
+ return nonFunctionTypePanic('NumIn', this)
1810
+ }
1811
+
1812
+ public In(_i: number): Type {
1813
+ return nonFunctionTypePanic('In', this)
1814
+ }
1815
+
1816
+ public NumOut(): number {
1817
+ return nonFunctionTypePanic('NumOut', this)
1818
+ }
1819
+
1820
+ public Out(_i: number): Type {
1821
+ return nonFunctionTypePanic('Out', this)
1822
+ }
1823
+
1824
+ public IsVariadic(): boolean {
1825
+ return nonFunctionTypePanic('IsVariadic', this)
1826
+ }
1827
+
1566
1828
  public Len(): number {
1567
1829
  return this._len
1568
1830
  }
@@ -1601,7 +1863,7 @@ class ArrayType implements Type {
1601
1863
  if (u.Kind() !== Interface) {
1602
1864
  throw new Error('reflect: non-interface type passed to Type.Implements')
1603
1865
  }
1604
- return false
1866
+ return typeImplementsInterface(this, u)
1605
1867
  }
1606
1868
 
1607
1869
  public AssignableTo(u: Type | null): boolean {
@@ -1638,7 +1900,10 @@ class ArrayType implements Type {
1638
1900
 
1639
1901
  // Pointer type implementation
1640
1902
  class PointerType implements Type {
1641
- constructor(private _elemType: Type) {}
1903
+ constructor(
1904
+ private _elemType: Type,
1905
+ private _methods: $.MethodSignature[] = [],
1906
+ ) {}
1642
1907
 
1643
1908
  public String(): string {
1644
1909
  return '*' + this._elemType.String()
@@ -1664,6 +1929,26 @@ class PointerType implements Type {
1664
1929
  return 0
1665
1930
  }
1666
1931
 
1932
+ public NumIn(): number {
1933
+ return nonFunctionTypePanic('NumIn', this)
1934
+ }
1935
+
1936
+ public In(_i: number): Type {
1937
+ return nonFunctionTypePanic('In', this)
1938
+ }
1939
+
1940
+ public NumOut(): number {
1941
+ return nonFunctionTypePanic('NumOut', this)
1942
+ }
1943
+
1944
+ public Out(_i: number): Type {
1945
+ return nonFunctionTypePanic('Out', this)
1946
+ }
1947
+
1948
+ public IsVariadic(): boolean {
1949
+ return nonFunctionTypePanic('IsVariadic', this)
1950
+ }
1951
+
1667
1952
  public PkgPath(): string {
1668
1953
  return ''
1669
1954
  }
@@ -1698,9 +1983,7 @@ class PointerType implements Type {
1698
1983
  if (u.Kind() !== Interface) {
1699
1984
  throw new Error('reflect: non-interface type passed to Type.Implements')
1700
1985
  }
1701
- // For pointer types, check if the element type implements the interface
1702
- const elemTypeName = this._elemType.String()
1703
- return typeImplementsInterface(elemTypeName, u)
1986
+ return typeImplementsInterface(this, u)
1704
1987
  }
1705
1988
 
1706
1989
  public AssignableTo(u: Type | null): boolean {
@@ -1728,10 +2011,18 @@ class PointerType implements Type {
1728
2011
  }
1729
2012
 
1730
2013
  public NumMethod(): number {
1731
- return 0
2014
+ return typeMethods(this).length
1732
2015
  }
1733
2016
  public MethodByName(name: string): [Method, boolean] {
1734
- return typeMethodByName(this._elemType, name)
2017
+ return typeMethodByName(this, name)
2018
+ }
2019
+
2020
+ public methodSignatures(): $.MethodSignature[] {
2021
+ return this._methods
2022
+ }
2023
+
2024
+ public mergeMethodSignatures(methods: $.MethodSignature[]): void {
2025
+ this._methods = mergeMethodSignatureList(this._methods, methods)
1735
2026
  }
1736
2027
 
1737
2028
  public Len(): number {
@@ -1744,10 +2035,54 @@ class PointerType implements Type {
1744
2035
  }
1745
2036
 
1746
2037
  // Function type implementation
2038
+ interface FunctionTypeDescriptor {
2039
+ name?: string
2040
+ signature?: string
2041
+ params?: Type[]
2042
+ results?: Type[]
2043
+ variadic?: boolean
2044
+ methods?: $.MethodSignature[]
2045
+ }
2046
+
1747
2047
  class FunctionType implements Type {
1748
- constructor(private _signature: string) {}
2048
+ private _name: string
2049
+ private _signature: string
2050
+ private _params: Type[]
2051
+ private _results: Type[]
2052
+ private _variadic: boolean
2053
+ private _hasSignature: boolean
2054
+ private _methods: $.MethodSignature[]
2055
+
2056
+ constructor(signatureOrDescriptor: string | FunctionTypeDescriptor) {
2057
+ if (typeof signatureOrDescriptor === 'string') {
2058
+ this._name = ''
2059
+ this._signature = signatureOrDescriptor
2060
+ this._params = []
2061
+ this._results = []
2062
+ this._variadic = false
2063
+ this._hasSignature = false
2064
+ this._methods = []
2065
+ return
2066
+ }
2067
+
2068
+ this._name = signatureOrDescriptor.name ?? ''
2069
+ this._params = signatureOrDescriptor.params ?? []
2070
+ this._results = signatureOrDescriptor.results ?? []
2071
+ this._variadic = signatureOrDescriptor.variadic ?? false
2072
+ this._hasSignature =
2073
+ signatureOrDescriptor.signature !== undefined ||
2074
+ signatureOrDescriptor.params !== undefined ||
2075
+ signatureOrDescriptor.results !== undefined
2076
+ this._methods = signatureOrDescriptor.methods ?? []
2077
+ this._signature =
2078
+ signatureOrDescriptor.signature ??
2079
+ formatFunctionSignature(this._params, this._results, this._variadic)
2080
+ }
1749
2081
 
1750
2082
  public String(): string {
2083
+ if (this._name !== '') {
2084
+ return this._name
2085
+ }
1751
2086
  return this._signature
1752
2087
  }
1753
2088
 
@@ -1771,12 +2106,54 @@ class FunctionType implements Type {
1771
2106
  return 0
1772
2107
  }
1773
2108
 
2109
+ public NumIn(): number {
2110
+ return this._params.length
2111
+ }
2112
+
2113
+ public In(i: number): Type {
2114
+ if (i < 0 || i >= this._params.length) {
2115
+ throw new Error(
2116
+ `reflect: In index out of range [${i}] with length ${this._params.length}`,
2117
+ )
2118
+ }
2119
+ return this._params[i]
2120
+ }
2121
+
2122
+ public NumOut(): number {
2123
+ return this._results.length
2124
+ }
2125
+
2126
+ public Out(i: number): Type {
2127
+ if (i < 0 || i >= this._results.length) {
2128
+ throw new Error(
2129
+ `reflect: Out index out of range [${i}] with length ${this._results.length}`,
2130
+ )
2131
+ }
2132
+ return this._results[i]
2133
+ }
2134
+
2135
+ public IsVariadic(): boolean {
2136
+ return this._variadic
2137
+ }
2138
+
1774
2139
  public PkgPath(): string {
2140
+ if (this._name !== '') {
2141
+ const dotIndex = this._name.lastIndexOf('.')
2142
+ if (dotIndex > 0) {
2143
+ return this._name.substring(0, dotIndex)
2144
+ }
2145
+ }
1775
2146
  return ''
1776
2147
  }
1777
2148
 
1778
2149
  public Name(): string {
1779
- // Function types are unnamed composite types
2150
+ if (this._name !== '') {
2151
+ const dotIndex = this._name.lastIndexOf('.')
2152
+ if (dotIndex >= 0) {
2153
+ return this._name.substring(dotIndex + 1)
2154
+ }
2155
+ return this._name
2156
+ }
1780
2157
  return ''
1781
2158
  }
1782
2159
 
@@ -1805,7 +2182,7 @@ class FunctionType implements Type {
1805
2182
  if (u.Kind() !== Interface) {
1806
2183
  throw new Error('reflect: non-interface type passed to Type.Implements')
1807
2184
  }
1808
- return false
2185
+ return typeImplementsInterface(this, u)
1809
2186
  }
1810
2187
 
1811
2188
  public AssignableTo(u: Type | null): boolean {
@@ -1829,10 +2206,29 @@ class FunctionType implements Type {
1829
2206
  }
1830
2207
 
1831
2208
  public NumMethod(): number {
1832
- return 0
2209
+ return typeMethods(this).length
1833
2210
  }
1834
- public MethodByName(_name: string): [Method, boolean] {
1835
- return [zeroMethod(), false]
2211
+ public MethodByName(name: string): [Method, boolean] {
2212
+ return typeMethodByName(this, name)
2213
+ }
2214
+
2215
+ public methodSignatures(): $.MethodSignature[] {
2216
+ return this._methods
2217
+ }
2218
+
2219
+ public mergeMethodSignatures(methods: $.MethodSignature[]): void {
2220
+ this._methods = mergeMethodSignatureList(this._methods, methods)
2221
+ }
2222
+
2223
+ public mergeSignature(source: FunctionType): void {
2224
+ if (!source._hasSignature || this._hasSignature) {
2225
+ return
2226
+ }
2227
+ this._params = source._params
2228
+ this._results = source._results
2229
+ this._variadic = source._variadic
2230
+ this._signature = source._signature
2231
+ this._hasSignature = true
1836
2232
  }
1837
2233
 
1838
2234
  public Len(): number {
@@ -1844,72 +2240,329 @@ class FunctionType implements Type {
1844
2240
  }
1845
2241
  }
1846
2242
 
1847
- // Map type implementation
1848
- class MapType implements Type {
1849
- constructor(
1850
- private _keyType: Type,
1851
- private _elemType: Type,
1852
- ) {}
1853
-
1854
- public String(): string {
1855
- return `map[${this._keyType.String()}]${this._elemType.String()}`
2243
+ function formatFunctionSignature(
2244
+ params: Type[],
2245
+ results: Type[],
2246
+ variadic: boolean,
2247
+ ): string {
2248
+ const paramStrings = params.map((param, index) => {
2249
+ const typeName = param.String()
2250
+ if (!variadic || index !== params.length - 1) {
2251
+ return typeName
2252
+ }
2253
+ if (typeName.startsWith('[]')) {
2254
+ return '...' + typeName.slice(2)
2255
+ }
2256
+ return '...' + typeName
2257
+ })
2258
+ let signature = `func(${paramStrings.join(', ')})`
2259
+ if (results.length === 1) {
2260
+ signature += ` ${results[0].String()}`
2261
+ } else if (results.length > 1) {
2262
+ signature += ` (${results.map((result) => result.String()).join(', ')})`
1856
2263
  }
2264
+ return signature
2265
+ }
1857
2266
 
1858
- public Kind(): Kind {
1859
- return Map
1860
- }
2267
+ async function callReflectFunction(
2268
+ fn: (...args: unknown[]) => unknown | Promise<unknown>,
2269
+ fnType: Type,
2270
+ inArgs: $.Slice<Value>,
2271
+ op: ReflectCallOp,
2272
+ ): Promise<$.Slice<Value>> {
2273
+ const args = $.asArray(inArgs)
2274
+ const rawArgs = reflectCallRawArgs(fnType, args, op)
2275
+ const result = await fn(...rawArgs)
2276
+ return normalizeReflectCallResults(fnType, result)
2277
+ }
1861
2278
 
1862
- public Comparable(): boolean {
1863
- return false
1864
- }
2279
+ type ReflectCallOp = 'Call' | 'CallSlice'
1865
2280
 
1866
- public Size(): number {
1867
- return 8 // map header size
2281
+ function reflectCallRawArgs(
2282
+ fnType: Type,
2283
+ args: Value[],
2284
+ op: ReflectCallOp,
2285
+ ): unknown[] {
2286
+ if (op === 'CallSlice') {
2287
+ return reflectCallSliceRawArgs(fnType, args)
1868
2288
  }
1869
-
1870
- public Elem(): Type {
1871
- return this._elemType
2289
+ if (!fnType.IsVariadic()) {
2290
+ validateReflectCallInputCount(fnType, args.length)
2291
+ return args.map((arg, index) =>
2292
+ reflectCallValueInterface(op, arg, fnType.In(index), index),
2293
+ )
1872
2294
  }
1873
-
1874
- public NumField(): number {
1875
- return 0
2295
+ const fixedCount = fnType.NumIn() - 1
2296
+ if (args.length < fixedCount) {
2297
+ throw new Error('reflect: Call with too few input arguments')
1876
2298
  }
1877
-
1878
- public Key(): Type {
1879
- return this._keyType
2299
+ const rawArgs: unknown[] = []
2300
+ for (let i = 0; i < fixedCount; i++) {
2301
+ rawArgs.push(reflectCallValueInterface(op, args[i], fnType.In(i), i))
1880
2302
  }
1881
-
1882
- public PkgPath(): string {
1883
- return ''
2303
+ const variadicElemType = fnType.In(fixedCount).Elem()
2304
+ const variadicValues = args.slice(fixedCount)
2305
+ for (let i = 0; i < variadicValues.length; i++) {
2306
+ const value = variadicValues[i]
2307
+ if (!value.IsValid()) {
2308
+ throw new Error(`reflect: ${op} using zero Value argument`)
2309
+ }
2310
+ if (!value.Type().AssignableTo(variadicElemType)) {
2311
+ throw new Error(
2312
+ `reflect: cannot use ${value.Type().String()} as type ${variadicElemType.String()} in ${op}`,
2313
+ )
2314
+ }
1884
2315
  }
2316
+ rawArgs.push($.arrayToSlice(variadicValues.map((value) => value.Interface())))
2317
+ return rawArgs
2318
+ }
1885
2319
 
1886
- public Name(): string {
1887
- // Map types are unnamed composite types
1888
- return ''
2320
+ function reflectCallSliceRawArgs(fnType: Type, args: Value[]): unknown[] {
2321
+ if (!fnType.IsVariadic()) {
2322
+ throw new Error('reflect: CallSlice of non-variadic function')
1889
2323
  }
1890
-
1891
- public Field(_i: number): StructField {
1892
- throw new Error('reflect: Field of non-struct type')
2324
+ const expected = fnType.NumIn()
2325
+ if (args.length < expected) {
2326
+ throw new Error('reflect: CallSlice with too few input arguments')
2327
+ }
2328
+ if (args.length > expected) {
2329
+ throw new Error('reflect: CallSlice with too many input arguments')
1893
2330
  }
2331
+ return args.map((arg, index) =>
2332
+ reflectCallValueInterface('CallSlice', arg, fnType.In(index), index),
2333
+ )
2334
+ }
1894
2335
 
1895
- public FieldByName(name: string): [StructField, boolean] {
1896
- return typeFieldByName(this, name)
2336
+ function reflectCallValueInterface(
2337
+ op: ReflectCallOp,
2338
+ value: Value,
2339
+ target: Type,
2340
+ _index: number,
2341
+ ): unknown {
2342
+ if (!value.IsValid()) {
2343
+ throw new Error(`reflect: ${op} using zero Value argument`)
1897
2344
  }
2345
+ if (!value.Type().AssignableTo(target)) {
2346
+ throw new Error(
2347
+ `reflect: ${op} using ${value.Type().String()} as type ${target.String()}`,
2348
+ )
2349
+ }
2350
+ return value.Interface()
2351
+ }
1898
2352
 
1899
- public FieldByNameFunc(
1900
- match: (name: string) => boolean,
1901
- ): [StructField, boolean] {
1902
- return typeFieldByNameFunc(this, match)
2353
+ function validateReflectCallInputCount(fnType: Type, actual: number): void {
2354
+ const expected = fnType.NumIn()
2355
+ if (actual !== expected) {
2356
+ throw new Error(
2357
+ `reflect: Call with ${actual} input arguments for function with ${expected} inputs`,
2358
+ )
1903
2359
  }
2360
+ }
1904
2361
 
1905
- public Implements(u: Type | null): boolean {
1906
- if (!u) {
1907
- return false
1908
- }
1909
- if (u.Kind() !== Interface) {
1910
- throw new Error('reflect: non-interface type passed to Type.Implements')
2362
+ function normalizeReflectCallResults(
2363
+ fnType: Type,
2364
+ result: unknown,
2365
+ ): $.Slice<Value> {
2366
+ const expected = fnType.NumOut()
2367
+ if (expected === 0) {
2368
+ if (result !== undefined) {
2369
+ throw new Error(
2370
+ 'reflect: Call returned 1 results for function with 0 outputs',
2371
+ )
1911
2372
  }
1912
- return false
2373
+ return $.makeSlice<Value>(0)
2374
+ }
2375
+ if (expected === 1) {
2376
+ return $.arrayToSlice([new Value(result as ReflectValue, fnType.Out(0))])
2377
+ }
2378
+ if (!globalThis.Array.isArray(result)) {
2379
+ throw new Error(
2380
+ `reflect: Call returned 1 results for function with ${expected} outputs`,
2381
+ )
2382
+ }
2383
+ if (result.length !== expected) {
2384
+ throw new Error(
2385
+ `reflect: Call returned ${result.length} results for function with ${expected} outputs`,
2386
+ )
2387
+ }
2388
+ return $.arrayToSlice(
2389
+ result.map(
2390
+ (value, index) => new Value(value as ReflectValue, fnType.Out(index)),
2391
+ ),
2392
+ )
2393
+ }
2394
+
2395
+ export function MakeFunc(
2396
+ typ: Type | null,
2397
+ fn:
2398
+ | ((args: $.Slice<Value>) => $.Slice<Value> | Promise<$.Slice<Value>>)
2399
+ | null,
2400
+ ): Value {
2401
+ if (!typ || typ.Kind() !== Func) {
2402
+ throw new Error('reflect: call of MakeFunc with non-Func type')
2403
+ }
2404
+ if (typeof fn !== 'function') {
2405
+ throw new Error('reflect.MakeFunc: nil implementation')
2406
+ }
2407
+ const typeInfo = functionTypeInfoFromType(typ)
2408
+ const wrapper = $.functionValue(async (...rawArgs: unknown[]) => {
2409
+ const args = makeFuncArgs(typ, rawArgs)
2410
+ const resultValues = $.asArray(await fn($.arrayToSlice(args)))
2411
+ validateMakeFuncResults(typ, resultValues)
2412
+ if (typ.NumOut() === 0) {
2413
+ return undefined
2414
+ }
2415
+ if (typ.NumOut() === 1) {
2416
+ return makeFuncReturnInterface(resultValues[0], typ.Out(0))
2417
+ }
2418
+ return resultValues.map((value, index) =>
2419
+ makeFuncReturnInterface(value, typ.Out(index)),
2420
+ )
2421
+ }, typeInfo)
2422
+ return new Value(wrapper, typ)
2423
+ }
2424
+
2425
+ function makeFuncArgs(typ: Type, rawArgs: unknown[]): Value[] {
2426
+ validateReflectCallInputCount(typ, rawArgs.length)
2427
+ return rawArgs.map((arg, index) => {
2428
+ const value = ValueOf(arg as ReflectValue)
2429
+ const target = typ.In(index)
2430
+ if (!value.Type().AssignableTo(target)) {
2431
+ throw new Error(
2432
+ `reflect.MakeFunc: cannot use ${value.Type().String()} as type ${target.String()} in argument ${index}`,
2433
+ )
2434
+ }
2435
+ return value
2436
+ })
2437
+ }
2438
+
2439
+ function validateMakeFuncResults(typ: Type, resultValues: Value[]): void {
2440
+ const expected = typ.NumOut()
2441
+ if (resultValues.length !== expected) {
2442
+ throw new Error(
2443
+ `reflect.MakeFunc: returned ${resultValues.length} results for function with ${expected} outputs`,
2444
+ )
2445
+ }
2446
+ for (let i = 0; i < resultValues.length; i++) {
2447
+ const result = resultValues[i]
2448
+ if (!result.IsValid()) {
2449
+ throw new Error(`reflect.MakeFunc: returned zero Value for result ${i}`)
2450
+ }
2451
+ const target = typ.Out(i)
2452
+ if (!result.Type().AssignableTo(target)) {
2453
+ throw new Error(
2454
+ `reflect.MakeFunc: cannot use ${result.Type().String()} as type ${target.String()} in result ${i}`,
2455
+ )
2456
+ }
2457
+ }
2458
+ }
2459
+
2460
+ function makeFuncReturnInterface(value: Value, target: Type): unknown {
2461
+ const raw = value.Interface()
2462
+ if (target.Kind() === Interface) {
2463
+ return raw
2464
+ }
2465
+ return unwrapGoInterfaceBox(raw)
2466
+ }
2467
+
2468
+ function unwrapGoInterfaceBox(value: unknown): unknown {
2469
+ if (
2470
+ value !== null &&
2471
+ value !== undefined &&
2472
+ typeof value === 'object' &&
2473
+ '__goValue' in value
2474
+ ) {
2475
+ return (value as { __goValue: unknown }).__goValue
2476
+ }
2477
+ return value
2478
+ }
2479
+
2480
+ // Map type implementation
2481
+ class MapType implements Type {
2482
+ constructor(
2483
+ private _keyType: Type,
2484
+ private _elemType: Type,
2485
+ ) {}
2486
+
2487
+ public String(): string {
2488
+ return `map[${this._keyType.String()}]${this._elemType.String()}`
2489
+ }
2490
+
2491
+ public Kind(): Kind {
2492
+ return Map
2493
+ }
2494
+
2495
+ public Comparable(): boolean {
2496
+ return false
2497
+ }
2498
+
2499
+ public Size(): number {
2500
+ return 8 // map header size
2501
+ }
2502
+
2503
+ public Elem(): Type {
2504
+ return this._elemType
2505
+ }
2506
+
2507
+ public NumField(): number {
2508
+ return 0
2509
+ }
2510
+
2511
+ public NumIn(): number {
2512
+ return nonFunctionTypePanic('NumIn', this)
2513
+ }
2514
+
2515
+ public In(_i: number): Type {
2516
+ return nonFunctionTypePanic('In', this)
2517
+ }
2518
+
2519
+ public NumOut(): number {
2520
+ return nonFunctionTypePanic('NumOut', this)
2521
+ }
2522
+
2523
+ public Out(_i: number): Type {
2524
+ return nonFunctionTypePanic('Out', this)
2525
+ }
2526
+
2527
+ public IsVariadic(): boolean {
2528
+ return nonFunctionTypePanic('IsVariadic', this)
2529
+ }
2530
+
2531
+ public Key(): Type {
2532
+ return this._keyType
2533
+ }
2534
+
2535
+ public PkgPath(): string {
2536
+ return ''
2537
+ }
2538
+
2539
+ public Name(): string {
2540
+ // Map types are unnamed composite types
2541
+ return ''
2542
+ }
2543
+
2544
+ public Field(_i: number): StructField {
2545
+ throw new Error('reflect: Field of non-struct type')
2546
+ }
2547
+
2548
+ public FieldByName(name: string): [StructField, boolean] {
2549
+ return typeFieldByName(this, name)
2550
+ }
2551
+
2552
+ public FieldByNameFunc(
2553
+ match: (name: string) => boolean,
2554
+ ): [StructField, boolean] {
2555
+ return typeFieldByNameFunc(this, match)
2556
+ }
2557
+
2558
+ public Implements(u: Type | null): boolean {
2559
+ if (!u) {
2560
+ return false
2561
+ }
2562
+ if (u.Kind() !== Interface) {
2563
+ throw new Error('reflect: non-interface type passed to Type.Implements')
2564
+ }
2565
+ return typeImplementsInterface(this, u)
1913
2566
  }
1914
2567
 
1915
2568
  public AssignableTo(u: Type | null): boolean {
@@ -1949,61 +2602,174 @@ class MapType implements Type {
1949
2602
  }
1950
2603
 
1951
2604
  // Struct type implementation
1952
- /**
1953
- * Helper function to check if a type's method set contains all methods
1954
- * required by an interface.
1955
- *
1956
- * @param typeName The name of the type to check (e.g., "main.MyType")
1957
- * @param interfaceType The interface type that must be implemented
1958
- * @returns True if the type implements the interface, false otherwise
1959
- */
1960
- function typeImplementsInterface(
1961
- typeName: string,
1962
- interfaceType: Type,
1963
- ): boolean {
1964
- // Get the interface name and look it up in the type registry
1965
- const interfaceName =
1966
- interfaceType instanceof InterfaceType ?
1967
- interfaceType.registeredName() || interfaceType.String()
1968
- : interfaceType.String()
1969
- const interfaceTypeInfo = builtinGetTypeByName(interfaceName)
1970
-
1971
- if (!interfaceTypeInfo || !isInterfaceTypeInfo(interfaceTypeInfo)) {
1972
- return false
2605
+ function typeImplementsInterface(t: Type, interfaceType: Type): boolean {
2606
+ if (interfaceType.Kind() !== Interface) {
2607
+ throw new Error('reflect: non-interface type passed to Type.Implements')
2608
+ }
2609
+ const requiredMethods = typeMethods(interfaceType)
2610
+ if (requiredMethods.length === 0) {
2611
+ return true
1973
2612
  }
2613
+ const methods = typeMethods(t)
2614
+ return requiredMethods.every((requiredMethod) => {
2615
+ const method = methods.find(
2616
+ (candidate) => candidate.name === requiredMethod.name,
2617
+ )
2618
+ return (
2619
+ method !== undefined && methodSignatureIdentical(method, requiredMethod)
2620
+ )
2621
+ })
2622
+ }
1974
2623
 
1975
- // Get the type info for the struct/type
1976
- const typeInfo = builtinGetTypeByName(typeName)
2624
+ function methodSignatureIdentical(
2625
+ actual: $.MethodSignature,
2626
+ required: $.MethodSignature,
2627
+ ): boolean {
2628
+ return (
2629
+ methodArgListIdentical(actual.args, required.args) &&
2630
+ methodArgListIdentical(actual.returns, required.returns)
2631
+ )
2632
+ }
1977
2633
 
1978
- if (!typeInfo || !isStructTypeInfo(typeInfo)) {
2634
+ function methodArgListIdentical(
2635
+ actual: $.MethodArg[],
2636
+ required: $.MethodArg[],
2637
+ ): boolean {
2638
+ if (actual.length !== required.length) {
1979
2639
  return false
1980
2640
  }
2641
+ return actual.every(
2642
+ (arg, index) =>
2643
+ methodArgIdentityKey(arg) === methodArgIdentityKey(required[index]),
2644
+ )
2645
+ }
1981
2646
 
1982
- // Check if the type has all required methods
1983
- const requiredMethods = interfaceTypeInfo.methods || []
1984
- const typeMethods = typeInfo.methods || []
2647
+ function methodArgIdentityKey(arg: $.MethodArg): string {
2648
+ return typeInfoIdentityKey(arg.type, new Set())
2649
+ }
1985
2650
 
1986
- // For each required method, check if the type has a matching method
1987
- for (const requiredMethod of requiredMethods) {
1988
- const typeMethod = typeMethods.find((m) => m.name === requiredMethod.name)
2651
+ function methodSignatureIdentityKey(method: $.MethodSignature): string {
2652
+ const args = method.args.map(methodArgIdentityKey).join(',')
2653
+ const returns = method.returns.map(methodArgIdentityKey).join(',')
2654
+ return `${method.name}(${args})(${returns})`
2655
+ }
1989
2656
 
1990
- if (!typeMethod) {
1991
- return false
2657
+ function mergeMethodSignatureList(
2658
+ existing: $.MethodSignature[],
2659
+ incoming: $.MethodSignature[],
2660
+ ): $.MethodSignature[] {
2661
+ if (incoming.length === 0) {
2662
+ return existing
2663
+ }
2664
+ const merged = [...existing]
2665
+ for (const method of incoming) {
2666
+ const existingIndex = merged.findIndex(
2667
+ (candidate) => candidate.name === method.name,
2668
+ )
2669
+ if (existingIndex === -1) {
2670
+ merged.push(method)
2671
+ continue
1992
2672
  }
1993
-
1994
- // Check if method signatures match (simplified - just check counts)
1995
- if (typeMethod.args.length !== requiredMethod.args.length) {
1996
- return false
2673
+ if (
2674
+ methodSignatureIdentityKey(merged[existingIndex]) !==
2675
+ methodSignatureIdentityKey(method)
2676
+ ) {
2677
+ merged[existingIndex] = method
1997
2678
  }
2679
+ }
2680
+ return merged.sort((left, right) => left.name.localeCompare(right.name))
2681
+ }
1998
2682
 
1999
- if (typeMethod.returns.length !== requiredMethod.returns.length) {
2000
- return false
2683
+ function typeInfoIdentityKey(
2684
+ info: $.TypeInfo | string,
2685
+ seen: Set<string>,
2686
+ ): string {
2687
+ if (typeof info === 'string') {
2688
+ const registered = builtinGetTypeByName(info)
2689
+ if (!registered) {
2690
+ return `named:${info}`
2001
2691
  }
2002
-
2003
- // Could add deeper type checking here, but for now this is sufficient
2692
+ const registeredName = registered.name ?? info
2693
+ if (registeredName !== '') {
2694
+ return `named:${registeredName}`
2695
+ }
2696
+ if (seen.has(info)) {
2697
+ return `named:${info}`
2698
+ }
2699
+ seen.add(info)
2700
+ const key = typeInfoIdentityKey(registered, seen)
2701
+ seen.delete(info)
2702
+ return key
2703
+ }
2704
+ switch (info.kind) {
2705
+ case $.TypeKind.Basic:
2706
+ if (info.typeName) {
2707
+ return `named:${info.typeName}`
2708
+ }
2709
+ return `basic:${info.name ?? 'unknown'}`
2710
+ case $.TypeKind.Interface:
2711
+ if (info.name) {
2712
+ return `named:${info.name}`
2713
+ }
2714
+ return `interface:${(info.methods ?? [])
2715
+ .map(methodSignatureIdentityKey)
2716
+ .join('|')}`
2717
+ case $.TypeKind.Struct:
2718
+ if (info.name) {
2719
+ return `named:${info.name}`
2720
+ }
2721
+ return `struct:${(info.fields ?? [])
2722
+ .map(
2723
+ (field) =>
2724
+ [
2725
+ field.name,
2726
+ field.pkgPath ?? '',
2727
+ field.tag ?? '',
2728
+ field.anonymous === true ? 'anonymous' : 'named',
2729
+ typeInfoIdentityKey(field.type, seen),
2730
+ ].join('\u0000'),
2731
+ )
2732
+ .join('\u0001')}`
2733
+ case $.TypeKind.Pointer:
2734
+ return `ptr:${typeInfoIdentityKey(
2735
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2736
+ seen,
2737
+ )}`
2738
+ case $.TypeKind.Slice:
2739
+ return `slice:${typeInfoIdentityKey(
2740
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2741
+ seen,
2742
+ )}`
2743
+ case $.TypeKind.Array:
2744
+ return `array:${info.length}:${typeInfoIdentityKey(
2745
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2746
+ seen,
2747
+ )}`
2748
+ case $.TypeKind.Map:
2749
+ return `map:${typeInfoIdentityKey(
2750
+ info.keyType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2751
+ seen,
2752
+ )}:${typeInfoIdentityKey(
2753
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2754
+ seen,
2755
+ )}`
2756
+ case $.TypeKind.Function:
2757
+ if (info.name) {
2758
+ return `named:${info.name}`
2759
+ }
2760
+ return `func:${info.isVariadic === true}:${(info.params ?? [])
2761
+ .map((param) => typeInfoIdentityKey(param, seen))
2762
+ .join(',')}:${(info.results ?? [])
2763
+ .map((result) => typeInfoIdentityKey(result, seen))
2764
+ .join(',')}`
2765
+ case $.TypeKind.Channel:
2766
+ return `chan:${info.direction ?? 'both'}:${typeInfoIdentityKey(
2767
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2768
+ seen,
2769
+ )}`
2770
+ default:
2771
+ return 'unknown'
2004
2772
  }
2005
-
2006
- return true
2007
2773
  }
2008
2774
 
2009
2775
  function typeFieldByName(t: Type, name: string): [StructField, boolean] {
@@ -2017,8 +2783,7 @@ function typeFieldByNameFunc(
2017
2783
  if (t.Kind() !== Struct) {
2018
2784
  throw new Error('reflect: FieldByName of non-struct type')
2019
2785
  }
2020
- for (let i = 0; i < t.NumField(); i++) {
2021
- const field = t.Field(i)
2786
+ for (const field of visibleStructFields(t)) {
2022
2787
  if (match(field.Name)) {
2023
2788
  return [field, true]
2024
2789
  }
@@ -2026,6 +2791,59 @@ function typeFieldByNameFunc(
2026
2791
  return [new StructField(), false]
2027
2792
  }
2028
2793
 
2794
+ export function visibleStructFields(t: Type): StructField[] {
2795
+ const fields: StructField[] = []
2796
+ const byName = new globalThis.Map<string, number>()
2797
+ const visiting = new Set<Type>()
2798
+ const index: number[] = []
2799
+
2800
+ const walk = (typ: Type): void => {
2801
+ if (visiting.has(typ)) {
2802
+ return
2803
+ }
2804
+ visiting.add(typ)
2805
+ for (let i = 0; i < typ.NumField(); i++) {
2806
+ const field = typ.Field(i).clone()
2807
+ index.push(i)
2808
+
2809
+ let add = true
2810
+ const oldIndex = byName.get(field.Name)
2811
+ if (oldIndex !== undefined) {
2812
+ const old = fields[oldIndex]
2813
+ if (index.length === old.Index.length) {
2814
+ old.Name = ''
2815
+ add = false
2816
+ } else if (index.length < old.Index.length) {
2817
+ old.Name = ''
2818
+ } else {
2819
+ add = false
2820
+ }
2821
+ }
2822
+ if (add) {
2823
+ field.Index = [...index]
2824
+ byName.set(field.Name, fields.length)
2825
+ fields.push(field)
2826
+ }
2827
+
2828
+ if (field.Anonymous) {
2829
+ let fieldType = field.Type
2830
+ if (fieldType.Kind() === Ptr) {
2831
+ fieldType = fieldType.Elem()
2832
+ }
2833
+ if (fieldType.Kind() === Struct) {
2834
+ walk(fieldType)
2835
+ }
2836
+ }
2837
+
2838
+ index.pop()
2839
+ }
2840
+ visiting.delete(typ)
2841
+ }
2842
+
2843
+ walk(t)
2844
+ return fields.filter((field) => field.Name !== '')
2845
+ }
2846
+
2029
2847
  function zeroMethod(): Method {
2030
2848
  return {
2031
2849
  Name: '',
@@ -2038,17 +2856,65 @@ function zeroMethod(): Method {
2038
2856
  function methodFromSignature(
2039
2857
  signature: $.MethodSignature,
2040
2858
  index: number,
2859
+ receiver: Type,
2041
2860
  ): Method {
2042
2861
  return {
2043
2862
  Name: signature.name,
2044
- Type: new FunctionType('func'),
2863
+ Type: methodTypeFromSignature(
2864
+ signature,
2865
+ receiver,
2866
+ receiver.Kind() !== Interface,
2867
+ ),
2045
2868
  Func: () => undefined,
2046
2869
  Index: index,
2047
2870
  }
2048
2871
  }
2049
2872
 
2873
+ function methodTypeFromSignature(
2874
+ signature: $.MethodSignature,
2875
+ receiver: Type,
2876
+ includeReceiver: boolean,
2877
+ ): Type {
2878
+ const params = signature.args.map(methodArgType)
2879
+ if (includeReceiver) {
2880
+ params.unshift(receiver)
2881
+ }
2882
+ return new FunctionType({
2883
+ params,
2884
+ results: signature.returns.map(methodArgType),
2885
+ })
2886
+ }
2887
+
2888
+ function methodArgType(arg: $.MethodArg): Type {
2889
+ return typeFromTypeInfoWithSeen(arg.type, new Set())
2890
+ }
2891
+
2050
2892
  function typeMethods(t: Type): $.MethodSignature[] {
2051
- const typeInfo = builtinGetTypeByName(t.String())
2893
+ let typeInfo = builtinGetTypeByName(t.String())
2894
+ if (!typeInfo && t.Kind() === Ptr) {
2895
+ typeInfo = builtinGetTypeByName(t.Elem().String())
2896
+ }
2897
+ if (!typeInfo && t instanceof InterfaceType) {
2898
+ const registeredName = t.registeredName()
2899
+ if (registeredName) {
2900
+ typeInfo = builtinGetTypeByName(registeredName)
2901
+ }
2902
+ }
2903
+ if (!typeInfo && t instanceof InterfaceType) {
2904
+ return t.methodSignatures()
2905
+ }
2906
+ if (!typeInfo && t instanceof PointerType) {
2907
+ return mergeMethodSignatureList(
2908
+ typeMethods(t.Elem()),
2909
+ t.methodSignatures(),
2910
+ )
2911
+ }
2912
+ if (!typeInfo && t instanceof BasicType) {
2913
+ return t.methodSignatures()
2914
+ }
2915
+ if (!typeInfo && t instanceof FunctionType) {
2916
+ return t.methodSignatures()
2917
+ }
2052
2918
  if (!typeInfo) {
2053
2919
  return []
2054
2920
  }
@@ -2058,30 +2924,119 @@ function typeMethods(t: Type): $.MethodSignature[] {
2058
2924
  return []
2059
2925
  }
2060
2926
 
2061
- function typeMethodByName(t: Type, name: string): [Method, boolean] {
2927
+ function methodSignatureByName(
2928
+ t: Type,
2929
+ name: string,
2930
+ ): [$.MethodSignature | undefined, number] {
2062
2931
  const methods = typeMethods(t)
2063
2932
  const index = methods.findIndex((method) => method.name === name)
2064
2933
  if (index === -1) {
2934
+ return [undefined, -1]
2935
+ }
2936
+ return [methods[index], index]
2937
+ }
2938
+
2939
+ function typeMethodByName(t: Type, name: string): [Method, boolean] {
2940
+ const [signature, index] = methodSignatureByName(t, name)
2941
+ if (!signature) {
2065
2942
  return [zeroMethod(), false]
2066
2943
  }
2067
- return [methodFromSignature(methods[index], index), true]
2944
+ return [methodFromSignature(signature, index, t), true]
2068
2945
  }
2069
2946
 
2070
2947
  function typeAssignableTo(t: Type, u: Type | null): boolean {
2071
2948
  if (u === null) {
2072
2949
  return false
2073
2950
  }
2074
- return t.String() === u.String() || t.Implements(u)
2951
+ if (typeIdentityKey(t) === typeIdentityKey(u)) {
2952
+ return true
2953
+ }
2954
+ if (
2955
+ (!typeIsNamed(t) || !typeIsNamed(u)) &&
2956
+ typeUnderlyingIdentityKey(t) === typeUnderlyingIdentityKey(u)
2957
+ ) {
2958
+ return true
2959
+ }
2960
+ if (u.Kind() !== Interface) {
2961
+ return false
2962
+ }
2963
+ return t.Implements(u)
2964
+ }
2965
+
2966
+ export function structFieldStorageKey(t: Type, i: number): string {
2967
+ if (t instanceof StructType) {
2968
+ return t.fieldKey(i)
2969
+ }
2970
+ return t.Field(i).Name
2971
+ }
2972
+
2973
+ interface StructFieldDescriptor {
2974
+ name: string
2975
+ key: string
2976
+ type: Type
2977
+ tag?: string
2978
+ pkgPath: string
2979
+ anonymous: boolean
2980
+ index: number[]
2981
+ offset: number
2982
+ exported: boolean
2983
+ }
2984
+
2985
+ function typeAlignment(typ: Type): number {
2986
+ switch (typ.Kind()) {
2987
+ case Bool:
2988
+ case Int8:
2989
+ case Uint8:
2990
+ return 1
2991
+ case Int16:
2992
+ case Uint16:
2993
+ return 2
2994
+ case Int32:
2995
+ case Uint32:
2996
+ case Float32:
2997
+ case Complex64:
2998
+ return 4
2999
+ case Array:
3000
+ return typeAlignment(typ.Elem())
3001
+ case Struct: {
3002
+ let align = 1
3003
+ for (let i = 0; i < typ.NumField(); i++) {
3004
+ align = Math.max(align, typeAlignment(typ.Field(i).Type))
3005
+ }
3006
+ return align
3007
+ }
3008
+ default:
3009
+ return 8
3010
+ }
3011
+ }
3012
+
3013
+ function alignOffset(offset: number, alignment: number): number {
3014
+ if (alignment <= 1) {
3015
+ return offset
3016
+ }
3017
+ return Math.ceil(offset / alignment) * alignment
3018
+ }
3019
+
3020
+ function structDescriptorSize(fields: StructFieldDescriptor[]): number {
3021
+ let size = 0
3022
+ let alignment = 1
3023
+ for (const field of fields) {
3024
+ alignment = Math.max(alignment, typeAlignment(field.type))
3025
+ size = Math.max(size, field.offset + field.type.Size())
3026
+ }
3027
+ return alignOffset(size, alignment)
2075
3028
  }
2076
3029
 
2077
3030
  class StructType implements Type {
2078
3031
  constructor(
2079
3032
  private _name: string,
2080
- private _fields: Array<{ name: string; type: Type; tag?: string }> = [],
3033
+ private _fields: StructFieldDescriptor[] = [],
3034
+ private _pkgPath = '',
3035
+ private _string = _name,
2081
3036
  ) {}
2082
3037
 
2083
3038
  public String(): string {
2084
- return this._name
3039
+ return this._string
2085
3040
  }
2086
3041
 
2087
3042
  public Kind(): Kind {
@@ -2093,8 +3048,7 @@ class StructType implements Type {
2093
3048
  }
2094
3049
 
2095
3050
  public Size(): number {
2096
- // Struct size is implementation-defined, we'll use a reasonable default
2097
- return this._fields.reduce((sum, field) => sum + field.type.Size(), 0)
3051
+ return structDescriptorSize(this._fields)
2098
3052
  }
2099
3053
 
2100
3054
  public Elem(): Type {
@@ -2105,7 +3059,33 @@ class StructType implements Type {
2105
3059
  return this._fields.length
2106
3060
  }
2107
3061
 
3062
+ public NumIn(): number {
3063
+ return nonFunctionTypePanic('NumIn', this)
3064
+ }
3065
+
3066
+ public In(_i: number): Type {
3067
+ return nonFunctionTypePanic('In', this)
3068
+ }
3069
+
3070
+ public NumOut(): number {
3071
+ return nonFunctionTypePanic('NumOut', this)
3072
+ }
3073
+
3074
+ public Out(_i: number): Type {
3075
+ return nonFunctionTypePanic('Out', this)
3076
+ }
3077
+
3078
+ public IsVariadic(): boolean {
3079
+ return nonFunctionTypePanic('IsVariadic', this)
3080
+ }
3081
+
2108
3082
  public PkgPath(): string {
3083
+ if (this._pkgPath !== '') {
3084
+ return this._pkgPath
3085
+ }
3086
+ if (this._name === '') {
3087
+ return ''
3088
+ }
2109
3089
  // Extract package path from full type name (e.g., "main.Person" -> "main")
2110
3090
  const dotIndex = this._name.lastIndexOf('.')
2111
3091
  if (dotIndex > 0) {
@@ -2115,6 +3095,9 @@ class StructType implements Type {
2115
3095
  }
2116
3096
 
2117
3097
  public Name(): string {
3098
+ if (this._name === '') {
3099
+ return ''
3100
+ }
2118
3101
  // Extract type name from full type name (e.g., "main.Person" -> "Person")
2119
3102
  const dotIndex = this._name.lastIndexOf('.')
2120
3103
  if (dotIndex >= 0) {
@@ -2132,13 +3115,68 @@ class StructType implements Type {
2132
3115
  const f = this._fields[i]
2133
3116
  return new StructField({
2134
3117
  Name: f.name,
2135
- PkgPath: '',
3118
+ PkgPath: f.pkgPath,
2136
3119
  Type: f.type,
2137
3120
  Tag: f.tag ? new StructTag(f.tag) : undefined,
2138
- Index: [i],
3121
+ Offset: f.offset,
3122
+ Index: [...f.index],
3123
+ Anonymous: f.anonymous,
2139
3124
  })
2140
3125
  }
2141
3126
 
3127
+ public fieldKey(i: number): string {
3128
+ if (i < 0 || i >= this.NumField()) {
3129
+ throw new Error(
3130
+ `reflect: Field index out of range [${i}] with length ${this.NumField()}`,
3131
+ )
3132
+ }
3133
+ return this._fields[i].key
3134
+ }
3135
+
3136
+ public descriptors(): StructFieldDescriptor[] {
3137
+ return this._fields.map((field) => ({
3138
+ ...field,
3139
+ index: [...field.index],
3140
+ }))
3141
+ }
3142
+
3143
+ public replaceDescriptors(fields: StructFieldDescriptor[]): void {
3144
+ this._fields = fields
3145
+ }
3146
+
3147
+ public identityKey(seen: Set<Type>): string {
3148
+ if (this._name !== '') {
3149
+ return `struct:${this._name}`
3150
+ }
3151
+ const fields = this._fields
3152
+ .map((field) =>
3153
+ [
3154
+ field.name,
3155
+ field.pkgPath,
3156
+ field.tag ?? '',
3157
+ field.anonymous ? 'anonymous' : 'named',
3158
+ typeIdentityKey(field.type, seen),
3159
+ ].join('\u0000'),
3160
+ )
3161
+ .join('\u0001')
3162
+ return `struct:${this._pkgPath}:${this._name}:${fields}`
3163
+ }
3164
+
3165
+ public underlyingIdentityKey(seen: Set<Type>): string {
3166
+ const fields = this._fields
3167
+ .map((field) =>
3168
+ [
3169
+ field.name,
3170
+ field.pkgPath,
3171
+ field.tag ?? '',
3172
+ field.anonymous ? 'anonymous' : 'named',
3173
+ typeIdentityKey(field.type, seen),
3174
+ ].join('\u0000'),
3175
+ )
3176
+ .join('\u0001')
3177
+ return `struct:${fields}`
3178
+ }
3179
+
2142
3180
  public FieldByName(name: string): [StructField, boolean] {
2143
3181
  return typeFieldByName(this, name)
2144
3182
  }
@@ -2160,7 +3198,7 @@ class StructType implements Type {
2160
3198
  if (u.Kind() !== Interface) {
2161
3199
  throw new Error('reflect: non-interface type passed to Type.Implements')
2162
3200
  }
2163
- return typeImplementsInterface(this._name, u)
3201
+ return typeImplementsInterface(this, u)
2164
3202
  }
2165
3203
 
2166
3204
  public AssignableTo(u: Type | null): boolean {
@@ -2201,7 +3239,7 @@ class StructType implements Type {
2201
3239
  throw new Error('reflect: call of reflect.Type.Bits on struct Type')
2202
3240
  }
2203
3241
 
2204
- static createTypeFromFieldInfo(ti: any): Type {
3242
+ static createTypeFromFieldInfo(ti: any, seen = new Set<string>()): Type {
2205
3243
  if (typeof ti === 'string') {
2206
3244
  return basicTypeFromName(ti === 'number' ? 'int' : ti)
2207
3245
  } else if (ti && ti.kind) {
@@ -2214,21 +3252,29 @@ class StructType implements Type {
2214
3252
  case 'slice':
2215
3253
  if (ti.elemType) {
2216
3254
  return new SliceType(
2217
- StructType.createTypeFromFieldInfo(ti.elemType),
3255
+ StructType.createTypeFromFieldInfo(ti.elemType, seen),
2218
3256
  )
2219
3257
  }
2220
3258
  return new SliceType(new BasicType(Invalid, 'unknown', 8))
2221
3259
  case 'pointer':
2222
3260
  if (ti.elemType) {
2223
3261
  return new PointerType(
2224
- StructType.createTypeFromFieldInfo(ti.elemType),
3262
+ StructType.createTypeFromFieldInfo(ti.elemType, seen),
2225
3263
  )
2226
3264
  }
2227
3265
  return new PointerType(new BasicType(Invalid, 'unknown', 8))
2228
3266
  case 'interface':
2229
- return new InterfaceType(name)
2230
- case 'struct':
2231
- return new StructType(name, structFieldsFromTypeInfo(ti))
3267
+ return interfaceTypeFromInfo(ti, seen)
3268
+ case 'struct': {
3269
+ const structName = ti.name ?? ''
3270
+ const fields = structFieldsFromTypeInfo(ti, seen)
3271
+ return new StructType(
3272
+ structName,
3273
+ fields,
3274
+ '',
3275
+ structName === '' ? structTypeString(fields) : structName,
3276
+ )
3277
+ }
2232
3278
  default:
2233
3279
  return new BasicType(Invalid, name, 8)
2234
3280
  }
@@ -2282,18 +3328,19 @@ function basicTypeFromName(name: string, typeName = ''): BasicType {
2282
3328
 
2283
3329
  function structFieldsFromTypeInfo(
2284
3330
  ti: $.StructTypeInfo,
2285
- ): Array<{ name: string; type: Type; tag?: string }> {
2286
- return Object.entries(ti.fields || {}).map(([name, fieldInfo]) => {
2287
- if (isStructFieldInfo(fieldInfo)) {
2288
- return {
2289
- name: fieldInfo.name ?? name,
2290
- type: typeFromTypeInfo(fieldInfo.type),
2291
- tag: fieldInfo.tag,
2292
- }
2293
- }
3331
+ seen = new Set<string>(),
3332
+ ): StructFieldDescriptor[] {
3333
+ return (ti.fields || []).map((fieldInfo, index) => {
2294
3334
  return {
2295
- name,
2296
- type: typeFromTypeInfo(fieldInfo),
3335
+ name: fieldInfo.name,
3336
+ key: structFieldRuntimeKey(fieldInfo),
3337
+ type: typeFromTypeInfoWithSeen(fieldInfo.type, seen),
3338
+ tag: fieldInfo.tag,
3339
+ pkgPath: fieldInfo.pkgPath ?? '',
3340
+ anonymous: fieldInfo.anonymous ?? false,
3341
+ index: fieldInfo.index ? [...fieldInfo.index] : [index],
3342
+ offset: fieldInfo.offset ?? index * 8,
3343
+ exported: fieldInfo.exported ?? (fieldInfo.pkgPath ?? '') === '',
2297
3344
  }
2298
3345
  })
2299
3346
  }
@@ -2339,6 +3386,26 @@ class ChannelType implements Type {
2339
3386
  return 0
2340
3387
  }
2341
3388
 
3389
+ public NumIn(): number {
3390
+ return nonFunctionTypePanic('NumIn', this)
3391
+ }
3392
+
3393
+ public In(_i: number): Type {
3394
+ return nonFunctionTypePanic('In', this)
3395
+ }
3396
+
3397
+ public NumOut(): number {
3398
+ return nonFunctionTypePanic('NumOut', this)
3399
+ }
3400
+
3401
+ public Out(_i: number): Type {
3402
+ return nonFunctionTypePanic('Out', this)
3403
+ }
3404
+
3405
+ public IsVariadic(): boolean {
3406
+ return nonFunctionTypePanic('IsVariadic', this)
3407
+ }
3408
+
2342
3409
  public PkgPath(): string {
2343
3410
  return ''
2344
3411
  }
@@ -2373,7 +3440,7 @@ class ChannelType implements Type {
2373
3440
  if (u.Kind() !== Interface) {
2374
3441
  throw new Error('reflect: non-interface type passed to Type.Implements')
2375
3442
  }
2376
- return false
3443
+ return typeImplementsInterface(this, u)
2377
3444
  }
2378
3445
 
2379
3446
  public AssignableTo(u: Type | null): boolean {
@@ -2421,6 +3488,7 @@ class InterfaceType implements Type {
2421
3488
  constructor(
2422
3489
  private _name: string = 'interface{}',
2423
3490
  private _registeredName?: string,
3491
+ private _methods: $.MethodSignature[] = [],
2424
3492
  ) {}
2425
3493
 
2426
3494
  public String(): string {
@@ -2447,6 +3515,26 @@ class InterfaceType implements Type {
2447
3515
  return 0
2448
3516
  }
2449
3517
 
3518
+ public NumIn(): number {
3519
+ return nonFunctionTypePanic('NumIn', this)
3520
+ }
3521
+
3522
+ public In(_i: number): Type {
3523
+ return nonFunctionTypePanic('In', this)
3524
+ }
3525
+
3526
+ public NumOut(): number {
3527
+ return nonFunctionTypePanic('NumOut', this)
3528
+ }
3529
+
3530
+ public Out(_i: number): Type {
3531
+ return nonFunctionTypePanic('Out', this)
3532
+ }
3533
+
3534
+ public IsVariadic(): boolean {
3535
+ return nonFunctionTypePanic('IsVariadic', this)
3536
+ }
3537
+
2450
3538
  public PkgPath(): string {
2451
3539
  if (this._name === 'interface{}' || this._name.startsWith('interface {')) {
2452
3540
  return ''
@@ -2487,8 +3575,14 @@ class InterfaceType implements Type {
2487
3575
  throw new Error('reflect: Key of non-map type')
2488
3576
  }
2489
3577
 
2490
- public Implements(_u: Type | null): boolean {
2491
- return false
3578
+ public Implements(u: Type | null): boolean {
3579
+ if (!u) {
3580
+ return false
3581
+ }
3582
+ if (u.Kind() !== Interface) {
3583
+ throw new Error('reflect: non-interface type passed to Type.Implements')
3584
+ }
3585
+ return typeImplementsInterface(this, u)
2492
3586
  }
2493
3587
 
2494
3588
  public AssignableTo(u: Type | null): boolean {
@@ -2536,6 +3630,10 @@ class InterfaceType implements Type {
2536
3630
  public registeredName(): string | undefined {
2537
3631
  return this._registeredName
2538
3632
  }
3633
+
3634
+ public methodSignatures(): $.MethodSignature[] {
3635
+ return this._methods
3636
+ }
2539
3637
  }
2540
3638
 
2541
3639
  function getTypeOf(value: ReflectValue): Type {
@@ -2583,24 +3681,20 @@ function getTypeOf(value: ReflectValue): Type {
2583
3681
  typeInfo.params &&
2584
3682
  typeInfo.results
2585
3683
  ) {
3684
+ if (funcWithMeta.__goTypeName && !typeInfo.name) {
3685
+ return functionTypeFromInfo({
3686
+ ...typeInfo,
3687
+ name: funcWithMeta.__goTypeName,
3688
+ })
3689
+ }
2586
3690
  return functionTypeFromInfo(typeInfo)
2587
3691
  }
2588
3692
  }
2589
3693
 
2590
3694
  // Then check for __goTypeName which indicates a typed function
2591
3695
  if (funcWithMeta.__goTypeName) {
2592
- // This is a typed Go function - try to reconstruct the signature
2593
3696
  const typeName = funcWithMeta.__goTypeName
2594
-
2595
- // For known Go function types, construct proper signatures
2596
- if (typeName === 'Greeter') {
2597
- return new FunctionType('func(string) string')
2598
- } else if (typeName === 'Adder') {
2599
- return new FunctionType('func(int, int) int')
2600
- }
2601
-
2602
- // Generic fallback for typed functions
2603
- return new FunctionType(`func`) // Could be enhanced with parameter parsing
3697
+ return new FunctionType({ name: typeName })
2604
3698
  }
2605
3699
 
2606
3700
  // For untyped functions, try to parse the signature
@@ -2734,6 +3828,19 @@ function getTypeOf(value: ReflectValue): Type {
2734
3828
  }
2735
3829
 
2736
3830
  // Check if it has a constructor with __typeInfo for proper struct names
3831
+ if (
3832
+ value &&
3833
+ typeof value === 'object' &&
3834
+ value.constructor &&
3835
+ '__reflectType' in value.constructor
3836
+ ) {
3837
+ const reflectType = (value.constructor as { __reflectType?: Type })
3838
+ .__reflectType
3839
+ if (reflectType) {
3840
+ return reflectType
3841
+ }
3842
+ }
3843
+
2737
3844
  if (
2738
3845
  value &&
2739
3846
  typeof value === 'object' &&
@@ -2741,34 +3848,19 @@ function getTypeOf(value: ReflectValue): Type {
2741
3848
  '__typeInfo' in value.constructor
2742
3849
  ) {
2743
3850
  const typeInfo = (
2744
- value.constructor as { __typeInfo?: { name?: string } }
3851
+ value.constructor as { __typeInfo?: $.StructTypeInfo }
2745
3852
  ).__typeInfo
2746
- if (typeInfo && typeInfo.name) {
2747
- const typeName =
2748
- typeInfo.name.includes('.') ?
2749
- typeInfo.name
2750
- : `main.${typeInfo.name}`
2751
- const regTypeInfo = builtinGetTypeByName(typeName)
2752
- let fields: Array<{ name: string; type: Type; tag?: string }> = []
2753
- if (regTypeInfo && isStructTypeInfo(regTypeInfo)) {
2754
- fields = Object.entries(regTypeInfo.fields || {}).map(
2755
- ([name, fieldInfo]) => {
2756
- // Check if fieldInfo is a StructFieldInfo with type and tag
2757
- if (isStructFieldInfo(fieldInfo)) {
2758
- return {
2759
- name: fieldInfo.name ?? name,
2760
- type: StructType.createTypeFromFieldInfo(fieldInfo.type),
2761
- tag: fieldInfo.tag,
2762
- }
2763
- }
2764
- // Otherwise it's just the type info directly (backwards compatible)
2765
- return {
2766
- name,
2767
- type: StructType.createTypeFromFieldInfo(fieldInfo),
2768
- }
2769
- },
2770
- )
3853
+ if (typeInfo && isStructTypeInfo(typeInfo)) {
3854
+ const name = typeInfo.name ?? ''
3855
+ if (name === '') {
3856
+ return new StructType('', structFieldsFromTypeInfo(typeInfo))
2771
3857
  }
3858
+ const typeName = name.includes('.') ? name : `main.${name}`
3859
+ const regTypeInfo = builtinGetTypeByName(typeName)
3860
+ const fields =
3861
+ regTypeInfo && isStructTypeInfo(regTypeInfo) ?
3862
+ structFieldsFromTypeInfo(regTypeInfo)
3863
+ : structFieldsFromTypeInfo(typeInfo)
2772
3864
  return new StructType(typeName, fields)
2773
3865
  }
2774
3866
  }
@@ -2832,20 +3924,168 @@ export function ChanOf(dir: ChanDir, t: Type): Type {
2832
3924
  return internType(new ChannelType(t, dir))
2833
3925
  }
2834
3926
 
3927
+ export function StructOf(fields: $.Slice<StructField>): Type {
3928
+ const inputFields = $.asArray(fields)
3929
+ const descriptors: StructFieldDescriptor[] = []
3930
+ const names = new Set<string>()
3931
+ let pkgPath = ''
3932
+ let offset = 0
3933
+ for (const [idx, field] of inputFields.entries()) {
3934
+ validateStructOfField(field, idx)
3935
+ if (field.PkgPath !== '') {
3936
+ if (pkgPath === '') {
3937
+ pkgPath = field.PkgPath
3938
+ } else if (pkgPath !== field.PkgPath) {
3939
+ throw new Error(
3940
+ `reflect.Struct: fields with different PkgPath ${pkgPath} and ${field.PkgPath}`,
3941
+ )
3942
+ }
3943
+ }
3944
+ if (names.has(field.Name) && field.Name !== '_') {
3945
+ throw new Error(`reflect.StructOf: duplicate field ${field.Name}`)
3946
+ }
3947
+ names.add(field.Name)
3948
+
3949
+ const fieldOffset = alignOffset(offset, typeAlignment(field.Type))
3950
+ const tag = field.Tag?.toString()
3951
+ const descriptor: StructFieldDescriptor = {
3952
+ name: field.Name,
3953
+ key: field.Name === '_' ? `_${idx}` : field.Name,
3954
+ type: field.Type,
3955
+ ...(tag ? { tag } : {}),
3956
+ pkgPath: field.PkgPath,
3957
+ anonymous: field.Anonymous,
3958
+ index: [idx],
3959
+ offset: fieldOffset,
3960
+ exported: field.IsExported(),
3961
+ }
3962
+ descriptors.push(descriptor)
3963
+ offset = fieldOffset + field.Type.Size()
3964
+ }
3965
+ return internType(
3966
+ new StructType('', descriptors, '', structTypeString(descriptors)),
3967
+ )
3968
+ }
3969
+
3970
+ function validateStructOfField(field: StructField, idx: number): void {
3971
+ if (field.Name === '') {
3972
+ throw new Error(`reflect.StructOf: field ${idx} has no name`)
3973
+ }
3974
+ if (!isValidStructFieldName(field.Name)) {
3975
+ throw new Error(`reflect.StructOf: field ${idx} has invalid name`)
3976
+ }
3977
+ if (!field.Type) {
3978
+ throw new Error(`reflect.StructOf: field ${idx} has no type`)
3979
+ }
3980
+ if (field.Anonymous && field.PkgPath !== '') {
3981
+ throw new Error(
3982
+ `reflect.StructOf: field "${field.Name}" is anonymous but has PkgPath set`,
3983
+ )
3984
+ }
3985
+ if (field.IsExported() && isUnexportedStructFieldName(field.Name)) {
3986
+ throw new Error(
3987
+ `reflect.StructOf: field "${field.Name}" is unexported but missing PkgPath`,
3988
+ )
3989
+ }
3990
+ validateAnonymousStructOfField(field)
3991
+ }
3992
+
3993
+ function isValidStructFieldName(name: string): boolean {
3994
+ return /^[\p{L}_][\p{L}\p{N}_]*$/u.test(name)
3995
+ }
3996
+
3997
+ function isUnexportedStructFieldName(name: string): boolean {
3998
+ const first = name.charCodeAt(0)
3999
+ return name[0] === '_' || (first >= 97 && first <= 122)
4000
+ }
4001
+
4002
+ function validateAnonymousStructOfField(field: StructField): void {
4003
+ if (!field.Anonymous) {
4004
+ return
4005
+ }
4006
+ const typ = field.Type
4007
+ if (typ.Kind() === Ptr) {
4008
+ const elem = typ.Elem()
4009
+ if (elem.Kind() === Ptr || elem.Kind() === Interface) {
4010
+ throw new Error(
4011
+ `reflect.StructOf: illegal embedded field type ${typ.String()}`,
4012
+ )
4013
+ }
4014
+ if (embeddedMethodCount(typ) > 0) {
4015
+ throw new Error('reflect: embedded type with methods not implemented')
4016
+ }
4017
+ return
4018
+ }
4019
+ if (embeddedMethodCount(typ) > 0) {
4020
+ throw new Error('reflect: embedded type with methods not implemented')
4021
+ }
4022
+ }
4023
+
4024
+ function embeddedMethodCount(typ: Type): number {
4025
+ if (typ.Kind() === Ptr) {
4026
+ return Math.max(typ.NumMethod(), typ.Elem().NumMethod())
4027
+ }
4028
+ return typ.NumMethod()
4029
+ }
4030
+
4031
+ function structTypeString(fields: StructFieldDescriptor[]): string {
4032
+ if (fields.length === 0) {
4033
+ return 'struct {}'
4034
+ }
4035
+ return `struct { ${fields.map(structFieldString).join('; ')} }`
4036
+ }
4037
+
4038
+ function structFieldString(field: StructFieldDescriptor): string {
4039
+ const tag = field.tag ? ` ${JSON.stringify(field.tag)}` : ''
4040
+ const prefix = field.anonymous ? '' : `${field.name} `
4041
+ return `${prefix}${field.type.String()}${tag}`
4042
+ }
4043
+
4044
+ export function FuncOf(
4045
+ inTypes: $.Slice<Type | null>,
4046
+ outTypes: $.Slice<Type | null>,
4047
+ variadic: boolean,
4048
+ ): Type {
4049
+ const params = $.asArray(inTypes).map(funcOfType)
4050
+ const results = $.asArray(outTypes).map(funcOfType)
4051
+ if (
4052
+ variadic &&
4053
+ (params.length === 0 || params[params.length - 1].Kind() !== Slice)
4054
+ ) {
4055
+ throw new Error('reflect.FuncOf: last arg of variadic func must be slice')
4056
+ }
4057
+ if (params.length + results.length > 128) {
4058
+ throw new Error('reflect.FuncOf: too many arguments')
4059
+ }
4060
+ return internType(new FunctionType({ params, results, variadic }))
4061
+ }
4062
+
4063
+ function funcOfType(typ: Type | null | undefined): Type {
4064
+ if (!typ) {
4065
+ throw new Error('reflect.FuncOf: nil Type')
4066
+ }
4067
+ return typ
4068
+ }
4069
+
2835
4070
  export function TypeFor(typeArgs?: $.GenericTypeArgs): Type {
2836
4071
  const descriptor = typeArgs?.T
4072
+ const methodSignatures = genericMethodSignatures(descriptor)
2837
4073
  if (descriptor?.type) {
2838
- return internType(typeFromTypeInfo(descriptor.type))
2839
- }
2840
- if (descriptor?.methods) {
2841
- const methods = Object.keys(descriptor.methods)
2842
- if (methods.length !== 0) {
2843
- return internType(
2844
- new InterfaceType(
2845
- `interface { ${methods.map((method) => method + '()').join('; ')} }`,
2846
- ),
2847
- )
2848
- }
4074
+ return internType(
4075
+ typeWithMethodSignatures(
4076
+ typeFromTypeInfo(descriptor.type),
4077
+ methodSignatures,
4078
+ ),
4079
+ )
4080
+ }
4081
+ if (methodSignatures.length !== 0) {
4082
+ return internType(
4083
+ new InterfaceType(
4084
+ interfaceTypeString(methodSignatures),
4085
+ undefined,
4086
+ methodSignatures,
4087
+ ),
4088
+ )
2849
4089
  }
2850
4090
  if (descriptor?.zero) {
2851
4091
  return internType(getTypeOf(descriptor.zero()))
@@ -2853,113 +4093,475 @@ export function TypeFor(typeArgs?: $.GenericTypeArgs): Type {
2853
4093
  return internType(new InterfaceType('interface{}'))
2854
4094
  }
2855
4095
 
4096
+ function genericMethodSignatures(
4097
+ descriptor: $.GenericTypeDescriptor | undefined,
4098
+ ): $.MethodSignature[] {
4099
+ if (!descriptor) {
4100
+ return []
4101
+ }
4102
+ if (descriptor.methodSignatures && descriptor.methodSignatures.length !== 0) {
4103
+ return descriptor.methodSignatures
4104
+ }
4105
+ if (!descriptor.methods) {
4106
+ return []
4107
+ }
4108
+ return Object.keys(descriptor.methods).map((method) => ({
4109
+ name: method,
4110
+ args: [],
4111
+ returns: [],
4112
+ }))
4113
+ }
4114
+
4115
+ function typeWithMethodSignatures(
4116
+ typ: Type,
4117
+ methods: $.MethodSignature[],
4118
+ ): Type {
4119
+ if (methods.length === 0) {
4120
+ return typ
4121
+ }
4122
+ if (typ instanceof BasicType) {
4123
+ typ.mergeMethodSignatures(methods)
4124
+ return typ
4125
+ }
4126
+ if (typ instanceof PointerType) {
4127
+ typ.mergeMethodSignatures(methods)
4128
+ return typ
4129
+ }
4130
+ if (typ instanceof FunctionType) {
4131
+ typ.mergeMethodSignatures(methods)
4132
+ return typ
4133
+ }
4134
+ return typ
4135
+ }
4136
+
2856
4137
  function typeFromTypeInfo(info: $.TypeInfo | string): Type {
4138
+ return typeFromTypeInfoWithSeen(info, new Set())
4139
+ }
4140
+
4141
+ function typeFromTypeInfoWithSeen(
4142
+ info: $.TypeInfo | string,
4143
+ seen: Set<string>,
4144
+ ): Type {
2857
4145
  if (typeof info === 'string') {
2858
4146
  const registered = builtinGetTypeByName(info)
2859
4147
  if (registered) {
2860
- return internType(typeFromTypeInfo(registered))
4148
+ const typ = typeFromTypeInfoWithSeen(registered, seen)
4149
+ return internType(typ)
2861
4150
  }
2862
- return internType(StructType.createTypeFromFieldInfo(info))
4151
+ return internType(StructType.createTypeFromFieldInfo(info, seen))
2863
4152
  }
4153
+ const recursiveName = recursiveTypeInfoName(info)
4154
+ if (recursiveName !== '') {
4155
+ const constructing = constructingRegisteredTypes.get(recursiveName)
4156
+ if (constructing) {
4157
+ return constructing
4158
+ }
4159
+ if (seen.has(recursiveName)) {
4160
+ return internType(shallowTypeFromRegisteredInfo(recursiveName, info))
4161
+ }
4162
+ if (info.kind === $.TypeKind.Struct) {
4163
+ const typ = new StructType(recursiveName, [])
4164
+ constructingRegisteredTypes.set(recursiveName, typ)
4165
+ seen.add(recursiveName)
4166
+ try {
4167
+ typ.replaceDescriptors(structFieldsFromTypeInfo(info, seen))
4168
+ return internType(typ)
4169
+ } finally {
4170
+ seen.delete(recursiveName)
4171
+ constructingRegisteredTypes.delete(recursiveName)
4172
+ }
4173
+ }
4174
+ seen.add(recursiveName)
4175
+ const typ = typeFromStructuredTypeInfoWithSeen(info, seen)
4176
+ seen.delete(recursiveName)
4177
+ return internType(typ)
4178
+ }
4179
+ return internType(typeFromStructuredTypeInfoWithSeen(info, seen))
4180
+ }
4181
+
4182
+ function recursiveTypeInfoName(info: $.TypeInfo): string {
4183
+ if (info.kind === $.TypeKind.Basic) {
4184
+ return info.typeName ?? ''
4185
+ }
4186
+ return info.name ?? ''
4187
+ }
4188
+
4189
+ function typeFromStructuredTypeInfoWithSeen(
4190
+ info: $.TypeInfo,
4191
+ seen: Set<string>,
4192
+ ): Type {
2864
4193
  switch (info.kind) {
2865
4194
  case $.TypeKind.Array:
2866
- return internType(
2867
- new ArrayType(
2868
- typeFromTypeInfo(
2869
- info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2870
- ),
2871
- info.length,
4195
+ return new ArrayType(
4196
+ typeFromTypeInfoWithSeen(
4197
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4198
+ seen,
2872
4199
  ),
4200
+ info.length,
2873
4201
  )
2874
4202
  case $.TypeKind.Basic:
2875
- return internType(StructType.createTypeFromFieldInfo(info))
4203
+ return StructType.createTypeFromFieldInfo(info, seen)
2876
4204
  case $.TypeKind.Channel:
2877
- return internType(
2878
- new ChannelType(
2879
- typeFromTypeInfo(
2880
- info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2881
- ),
2882
- chanDirFromTypeInfo(info.direction),
4205
+ return new ChannelType(
4206
+ typeFromTypeInfoWithSeen(
4207
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4208
+ seen,
2883
4209
  ),
4210
+ chanDirFromTypeInfo(info.direction),
2884
4211
  )
2885
4212
  case $.TypeKind.Function:
2886
- return internType(functionTypeFromInfo(info))
4213
+ return functionTypeFromInfo(info, seen)
2887
4214
  case $.TypeKind.Interface:
2888
- return internType(interfaceTypeFromInfo(info))
4215
+ return interfaceTypeFromInfo(info, seen)
2889
4216
  case $.TypeKind.Map:
2890
- return internType(
2891
- new MapType(
2892
- typeFromTypeInfo(
2893
- info.keyType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2894
- ),
2895
- typeFromTypeInfo(
2896
- info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2897
- ),
4217
+ return new MapType(
4218
+ typeFromTypeInfoWithSeen(
4219
+ info.keyType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4220
+ seen,
4221
+ ),
4222
+ typeFromTypeInfoWithSeen(
4223
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4224
+ seen,
2898
4225
  ),
2899
4226
  )
2900
4227
  case $.TypeKind.Slice:
2901
- return internType(
2902
- new SliceType(
2903
- typeFromTypeInfo(
2904
- info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2905
- ),
4228
+ return new SliceType(
4229
+ typeFromTypeInfoWithSeen(
4230
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4231
+ seen,
2906
4232
  ),
2907
4233
  )
2908
4234
  case $.TypeKind.Struct:
2909
- return internType(StructType.createTypeFromFieldInfo(info))
4235
+ return StructType.createTypeFromFieldInfo(info, seen)
2910
4236
  case $.TypeKind.Pointer:
2911
- return internType(
2912
- new PointerType(
2913
- typeFromTypeInfo(
2914
- info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2915
- ),
4237
+ return new PointerType(
4238
+ typeFromTypeInfoWithSeen(
4239
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4240
+ seen,
2916
4241
  ),
2917
4242
  )
2918
4243
  default:
2919
- return internType(StructType.createTypeFromFieldInfo(info))
4244
+ return StructType.createTypeFromFieldInfo(info, seen)
2920
4245
  }
2921
4246
  }
2922
4247
 
2923
- function functionTypeFromInfo(info: $.FunctionTypeInfo): Type {
2924
- if (info.name) {
2925
- return new FunctionType(info.name)
4248
+ function shallowTypeFromRegisteredInfo(name: string, info: $.TypeInfo): Type {
4249
+ switch (info.kind) {
4250
+ case $.TypeKind.Interface:
4251
+ return new InterfaceType(name, name, info.methods ?? [])
4252
+ case $.TypeKind.Struct:
4253
+ return new StructType(name, [])
4254
+ case $.TypeKind.Function:
4255
+ return new FunctionType({ name })
4256
+ case $.TypeKind.Basic:
4257
+ return StructType.createTypeFromFieldInfo({
4258
+ kind: $.TypeKind.Basic,
4259
+ name: info.name ?? 'unknown',
4260
+ typeName: info.typeName ?? name,
4261
+ })
4262
+ default:
4263
+ return StructType.createTypeFromFieldInfo(name)
2926
4264
  }
2927
- const params = info.params ?? []
2928
- const paramTypes = params.map((param, index) => {
2929
- const typeName = functionSignatureTypeName(param)
2930
- if (!info.isVariadic || index !== params.length - 1) {
2931
- return typeName
2932
- }
2933
- if (typeName.startsWith('[]')) {
2934
- return '...' + typeName.slice(2)
2935
- }
2936
- return '...' + typeName
4265
+ }
4266
+
4267
+ function functionTypeFromInfo(
4268
+ info: $.FunctionTypeInfo,
4269
+ seen = new Set<string>(),
4270
+ ): Type {
4271
+ const params = (info.params ?? []).map((param) =>
4272
+ typeFromTypeInfoWithSeen(param, seen),
4273
+ )
4274
+ const results = (info.results ?? []).map((result) =>
4275
+ typeFromTypeInfoWithSeen(result, seen),
4276
+ )
4277
+ return new FunctionType({
4278
+ name: info.name,
4279
+ params,
4280
+ results,
4281
+ variadic: info.isVariadic ?? false,
2937
4282
  })
2938
- const resultTypes = (info.results ?? []).map(functionSignatureTypeName)
2939
- let signature = `func(${paramTypes.join(', ')})`
2940
- if (resultTypes.length === 1) {
2941
- signature += ` ${resultTypes[0]}`
4283
+ }
4284
+
4285
+ function functionTypeInfoFromType(typ: Type): $.FunctionTypeInfo {
4286
+ const params: (string | $.TypeInfo)[] = []
4287
+ for (let i = 0; i < typ.NumIn(); i++) {
4288
+ params.push(typeInfoFromReflectType(typ.In(i)))
4289
+ }
4290
+ const results: (string | $.TypeInfo)[] = []
4291
+ for (let i = 0; i < typ.NumOut(); i++) {
4292
+ results.push(typeInfoFromReflectType(typ.Out(i)))
2942
4293
  }
2943
- if (resultTypes.length > 1) {
2944
- signature += ` (${resultTypes.join(', ')})`
4294
+ const info: $.FunctionTypeInfo = {
4295
+ kind: $.TypeKind.Function,
4296
+ params,
4297
+ results,
4298
+ }
4299
+ if (typ.Name() !== '') {
4300
+ info.name = typ.String()
4301
+ }
4302
+ if (typ.IsVariadic()) {
4303
+ info.isVariadic = true
4304
+ }
4305
+ return info
4306
+ }
4307
+
4308
+ export function typeInfoFromReflectType(typ: Type): string | $.TypeInfo {
4309
+ if (typ.PkgPath() !== '' && typ.Name() !== '') {
4310
+ return typ.String()
4311
+ }
4312
+ switch (typ.Kind()) {
4313
+ case Bool:
4314
+ case Int:
4315
+ case Int8:
4316
+ case Int16:
4317
+ case Int32:
4318
+ case Int64:
4319
+ case Uint:
4320
+ case Uint8:
4321
+ case Uint16:
4322
+ case Uint32:
4323
+ case Uint64:
4324
+ case Uintptr:
4325
+ case Float32:
4326
+ case Float64:
4327
+ case Complex64:
4328
+ case Complex128:
4329
+ case String:
4330
+ case UnsafePointer:
4331
+ return { kind: $.TypeKind.Basic, name: typ.String() }
4332
+ case Interface:
4333
+ return {
4334
+ kind: $.TypeKind.Interface,
4335
+ methods: typeMethods(typ).map((method) => ({
4336
+ name: method.name,
4337
+ args: method.args,
4338
+ returns: method.returns,
4339
+ })),
4340
+ }
4341
+ case Slice:
4342
+ return {
4343
+ kind: $.TypeKind.Slice,
4344
+ elemType: typeInfoFromReflectType(typ.Elem()),
4345
+ }
4346
+ case Array:
4347
+ return {
4348
+ kind: $.TypeKind.Array,
4349
+ elemType: typeInfoFromReflectType(typ.Elem()),
4350
+ length: typ.Len(),
4351
+ }
4352
+ case Ptr:
4353
+ return {
4354
+ kind: $.TypeKind.Pointer,
4355
+ elemType: typeInfoFromReflectType(typ.Elem()),
4356
+ }
4357
+ case Map:
4358
+ return {
4359
+ kind: $.TypeKind.Map,
4360
+ keyType: typeInfoFromReflectType(typ.Key()),
4361
+ elemType: typeInfoFromReflectType(typ.Elem()),
4362
+ }
4363
+ case Chan:
4364
+ return {
4365
+ kind: $.TypeKind.Channel,
4366
+ elemType: typeInfoFromReflectType(typ.Elem()),
4367
+ direction: channelDirectionFromString(typ.String()),
4368
+ }
4369
+ case Func:
4370
+ return functionTypeInfoFromType(typ)
4371
+ case Struct: {
4372
+ const fields =
4373
+ typ instanceof StructType ?
4374
+ typ.descriptors()
4375
+ : globalThis.Array.from({ length: typ.NumField() }, (_unused, idx) => {
4376
+ const field = typ.Field(idx)
4377
+ return {
4378
+ name: field.Name,
4379
+ key: structFieldStorageKey(typ, idx),
4380
+ type: field.Type,
4381
+ tag: field.Tag?.toString(),
4382
+ pkgPath: field.PkgPath,
4383
+ anonymous: field.Anonymous,
4384
+ index: [...field.Index],
4385
+ offset: field.Offset,
4386
+ exported: field.IsExported(),
4387
+ }
4388
+ })
4389
+ return {
4390
+ kind: $.TypeKind.Struct,
4391
+ name: typ.Name() === '' ? '' : typ.String(),
4392
+ methods: [],
4393
+ fields: fields.map((field) => ({
4394
+ name: field.name,
4395
+ key: field.key,
4396
+ type: typeInfoFromReflectType(field.type),
4397
+ ...(field.tag ? { tag: field.tag } : {}),
4398
+ ...(field.pkgPath ? { pkgPath: field.pkgPath } : {}),
4399
+ ...(field.anonymous ? { anonymous: true } : {}),
4400
+ index: [...field.index],
4401
+ offset: field.offset,
4402
+ exported: field.exported,
4403
+ })),
4404
+ }
4405
+ }
4406
+ default:
4407
+ return typ.String()
2945
4408
  }
2946
- return new FunctionType(signature)
2947
4409
  }
2948
4410
 
2949
- function functionSignatureTypeName(info: $.TypeInfo | string): string {
2950
- return typeFromTypeInfo(info).String()
4411
+ function channelDirectionFromString(
4412
+ typeName: string,
4413
+ ): 'send' | 'receive' | 'both' {
4414
+ if (typeName.startsWith('<-chan ')) {
4415
+ return 'receive'
4416
+ }
4417
+ if (typeName.startsWith('chan<- ')) {
4418
+ return 'send'
4419
+ }
4420
+ return 'both'
2951
4421
  }
2952
4422
 
2953
- function interfaceTypeFromInfo(info: $.InterfaceTypeInfo): Type {
2954
- if (info.methods.length === 0) {
2955
- return new InterfaceType('interface{}', info.name)
4423
+ function interfaceTypeFromInfo(
4424
+ info: $.InterfaceTypeInfo,
4425
+ seen = new Set<string>(),
4426
+ ): Type {
4427
+ const methods = info.methods ?? []
4428
+ if (methods.length === 0) {
4429
+ return new InterfaceType('interface{}', info.name, methods)
2956
4430
  }
2957
4431
  return new InterfaceType(
2958
- `interface { ${info.methods.map((method) => method.name + '()').join('; ')} }`,
4432
+ interfaceTypeString(methods, seen),
2959
4433
  info.name,
4434
+ methods,
2960
4435
  )
2961
4436
  }
2962
4437
 
4438
+ function interfaceTypeString(
4439
+ methods: $.MethodSignature[],
4440
+ seen = new Set<string>(),
4441
+ ): string {
4442
+ return `interface { ${methods
4443
+ .map((method) => interfaceMethodString(method, seen))
4444
+ .join('; ')} }`
4445
+ }
4446
+
4447
+ function interfaceMethodString(
4448
+ method: $.MethodSignature,
4449
+ seen: Set<string>,
4450
+ ): string {
4451
+ const args = method.args.map((arg) => methodArgString(arg, seen)).join(', ')
4452
+ const returns = method.returns.map((arg) => methodArgString(arg, seen))
4453
+ if (returns.length === 0) {
4454
+ return `${method.name}(${args})`
4455
+ }
4456
+ if (returns.length === 1) {
4457
+ return `${method.name}(${args}) ${returns[0]}`
4458
+ }
4459
+ return `${method.name}(${args}) (${returns.join(', ')})`
4460
+ }
4461
+
4462
+ function structTypeInfoString(
4463
+ info: $.StructTypeInfo,
4464
+ seen: Set<string>,
4465
+ ): string {
4466
+ if (info.name) {
4467
+ return info.name
4468
+ }
4469
+ const fields = info.fields ?? []
4470
+ if (fields.length === 0) {
4471
+ return 'struct {}'
4472
+ }
4473
+ return `struct { ${fields
4474
+ .map((field) => structFieldInfoString(field, seen))
4475
+ .join('; ')} }`
4476
+ }
4477
+
4478
+ function structFieldInfoString(
4479
+ field: $.StructFieldInfo,
4480
+ seen: Set<string>,
4481
+ ): string {
4482
+ const tag = field.tag ? ` ${JSON.stringify(field.tag)}` : ''
4483
+ const prefix = field.anonymous ? '' : `${field.name} `
4484
+ return `${prefix}${typeInfoString(field.type, seen)}${tag}`
4485
+ }
4486
+
4487
+ function methodArgString(arg: $.MethodArg, seen: Set<string>): string {
4488
+ return typeInfoString(arg.type, seen)
4489
+ }
4490
+
4491
+ function typeInfoString(info: $.TypeInfo | string, seen: Set<string>): string {
4492
+ if (typeof info === 'string') {
4493
+ return info
4494
+ }
4495
+ switch (info.kind) {
4496
+ case $.TypeKind.Basic:
4497
+ return info.typeName ?? info.name ?? 'unknown'
4498
+ case $.TypeKind.Interface: {
4499
+ const name = info.name ?? ''
4500
+ if (name !== '' && seen.has(name)) {
4501
+ return name
4502
+ }
4503
+ if (info.methods.length === 0) {
4504
+ return 'interface{}'
4505
+ }
4506
+ if (name !== '') {
4507
+ seen.add(name)
4508
+ }
4509
+ const text = interfaceTypeString(info.methods, seen)
4510
+ if (name !== '') {
4511
+ seen.delete(name)
4512
+ }
4513
+ return text
4514
+ }
4515
+ case $.TypeKind.Struct:
4516
+ return structTypeInfoString(info, seen)
4517
+ case $.TypeKind.Pointer:
4518
+ return `*${typeInfoString(
4519
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4520
+ seen,
4521
+ )}`
4522
+ case $.TypeKind.Slice:
4523
+ return `[]${typeInfoString(
4524
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4525
+ seen,
4526
+ )}`
4527
+ case $.TypeKind.Array:
4528
+ return `[${info.length}]${typeInfoString(
4529
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4530
+ seen,
4531
+ )}`
4532
+ case $.TypeKind.Map:
4533
+ return `map[${typeInfoString(
4534
+ info.keyType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4535
+ seen,
4536
+ )}]${typeInfoString(
4537
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4538
+ seen,
4539
+ )}`
4540
+ case $.TypeKind.Function: {
4541
+ const params = (info.params ?? [])
4542
+ .map((param) => typeInfoString(param, seen))
4543
+ .join(', ')
4544
+ const results = (info.results ?? []).map((result) =>
4545
+ typeInfoString(result, seen),
4546
+ )
4547
+ if (results.length === 0) {
4548
+ return `func(${params})`
4549
+ }
4550
+ if (results.length === 1) {
4551
+ return `func(${params}) ${results[0]}`
4552
+ }
4553
+ return `func(${params}) (${results.join(', ')})`
4554
+ }
4555
+ case $.TypeKind.Channel:
4556
+ return `chan ${typeInfoString(
4557
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4558
+ seen,
4559
+ )}`
4560
+ default:
4561
+ return 'unknown'
4562
+ }
4563
+ }
4564
+
2963
4565
  function chanDirFromTypeInfo(direction?: 'send' | 'receive' | 'both'): ChanDir {
2964
4566
  switch (direction) {
2965
4567
  case 'send':
@@ -2977,38 +4579,16 @@ function chanDirFromTypeInfo(direction?: 'send' | 'receive' | 'both'): ChanDir {
2977
4579
  */
2978
4580
  export function getInterfaceTypeByName(name: string): Type {
2979
4581
  const typeInfo = builtinGetTypeByName(name)
2980
- if (typeInfo && typeInfo.kind === TypeKind.Interface) {
2981
- return new InterfaceType(name, name)
4582
+ if (typeInfo && isInterfaceTypeInfo(typeInfo)) {
4583
+ return new InterfaceType(name, name, typeInfo.methods ?? [])
2982
4584
  }
2983
4585
  return new InterfaceType('interface{}')
2984
4586
  }
2985
4587
 
2986
4588
  export function getInterfaceLiteralTypeByName(name: string): Type {
2987
4589
  const typeInfo = builtinGetTypeByName(name)
2988
- if (typeInfo && typeInfo.kind === TypeKind.Interface) {
2989
- const methods = (typeInfo as any).methods || []
2990
- if (methods.length === 0) {
2991
- return new InterfaceType('interface{}', name)
2992
- }
2993
- const methodSigs = methods
2994
- .map((m: any) => {
2995
- const args =
2996
- m.args
2997
- ?.map((a: any) => (typeof a === 'string' ? a : 'any'))
2998
- .join(', ') || ''
2999
- const returns = m.returns?.map((r: any) =>
3000
- typeof r === 'string' ? r : 'any',
3001
- )
3002
- let returnSig = ''
3003
- if (returns && returns.length === 1) {
3004
- returnSig = ` ${returns[0]}`
3005
- } else if (returns && returns.length > 1) {
3006
- returnSig = ` (${returns.join(', ')})`
3007
- }
3008
- return `${m.name}(${args})${returnSig}`
3009
- })
3010
- .join('; ')
3011
- return new InterfaceType(`interface { ${methodSigs} }`, name)
4590
+ if (typeInfo && isInterfaceTypeInfo(typeInfo)) {
4591
+ return interfaceTypeFromInfo(typeInfo)
3012
4592
  }
3013
4593
  return new InterfaceType('interface{}')
3014
4594
  }