goscript 0.1.3 → 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 (330) 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} +35 -8
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/cmd/goscript/cmd_compile_test.go +105 -6
  8. package/compiler/build-flags.go +9 -10
  9. package/compiler/compile-request.go +12 -9
  10. package/compiler/compliance_test.go +0 -1
  11. package/compiler/config.go +2 -0
  12. package/compiler/gotest/request.go +28 -0
  13. package/compiler/gotest/runner.go +353 -27
  14. package/compiler/gotest/runner_test.go +400 -1
  15. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  16. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  17. package/compiler/lowered-program.go +24 -17
  18. package/compiler/lowering.go +988 -263
  19. package/compiler/lowering_bench_test.go +364 -0
  20. package/compiler/override-facts.go +15 -0
  21. package/compiler/override-parity-verifier.go +450 -0
  22. package/compiler/override-parity.go +122 -0
  23. package/compiler/override-registry_test.go +559 -0
  24. package/compiler/package-graph.go +61 -4
  25. package/compiler/package-graph_test.go +30 -0
  26. package/compiler/protobuf-ts-binding.go +514 -0
  27. package/compiler/protobuf-ts-binding_test.go +172 -0
  28. package/compiler/semantic-model-types.go +17 -4
  29. package/compiler/semantic-model.go +709 -72
  30. package/compiler/semantic-model_test.go +219 -0
  31. package/compiler/service.go +20 -1
  32. package/compiler/skeleton_test.go +1008 -20
  33. package/compiler/typescript-emitter.go +147 -15
  34. package/dist/gs/builtin/builtin.d.ts +2 -2
  35. package/dist/gs/builtin/builtin.js +20 -0
  36. package/dist/gs/builtin/builtin.js.map +1 -1
  37. package/dist/gs/builtin/slice.d.ts +2 -1
  38. package/dist/gs/builtin/slice.js +34 -4
  39. package/dist/gs/builtin/slice.js.map +1 -1
  40. package/dist/gs/builtin/type.d.ts +14 -6
  41. package/dist/gs/builtin/type.js +224 -64
  42. package/dist/gs/builtin/type.js.map +1 -1
  43. package/dist/gs/builtin/varRef.d.ts +11 -0
  44. package/dist/gs/builtin/varRef.js +57 -2
  45. package/dist/gs/builtin/varRef.js.map +1 -1
  46. package/dist/gs/bytes/buffer.gs.js +1 -1
  47. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  48. package/dist/gs/bytes/reader.gs.js +1 -1
  49. package/dist/gs/bytes/reader.gs.js.map +1 -1
  50. package/dist/gs/compress/zlib/index.d.ts +13 -6
  51. package/dist/gs/compress/zlib/index.js +131 -35
  52. package/dist/gs/compress/zlib/index.js.map +1 -1
  53. package/dist/gs/crypto/sha1/index.js +2 -5
  54. package/dist/gs/crypto/sha1/index.js.map +1 -1
  55. package/dist/gs/crypto/sha256/index.js +2 -5
  56. package/dist/gs/crypto/sha256/index.js.map +1 -1
  57. package/dist/gs/crypto/sha512/index.js +2 -5
  58. package/dist/gs/crypto/sha512/index.js.map +1 -1
  59. package/dist/gs/embed/index.d.ts +6 -0
  60. package/dist/gs/embed/index.js +210 -5
  61. package/dist/gs/embed/index.js.map +1 -1
  62. package/dist/gs/encoding/json/index.d.ts +114 -0
  63. package/dist/gs/encoding/json/index.js +544 -36
  64. package/dist/gs/encoding/json/index.js.map +1 -1
  65. package/dist/gs/fmt/fmt.d.ts +3 -3
  66. package/dist/gs/fmt/fmt.js +29 -16
  67. package/dist/gs/fmt/fmt.js.map +1 -1
  68. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
  69. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
  70. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  71. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  72. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  73. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  74. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  75. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  76. package/dist/gs/go/scanner/index.d.ts +2 -0
  77. package/dist/gs/go/scanner/index.js +29 -5
  78. package/dist/gs/go/scanner/index.js.map +1 -1
  79. package/dist/gs/go/token/index.js +22 -6
  80. package/dist/gs/go/token/index.js.map +1 -1
  81. package/dist/gs/hash/index.d.ts +6 -0
  82. package/dist/gs/hash/index.js +20 -0
  83. package/dist/gs/hash/index.js.map +1 -1
  84. package/dist/gs/internal/goarch/index.d.ts +43 -3
  85. package/dist/gs/internal/goarch/index.js +42 -10
  86. package/dist/gs/internal/goarch/index.js.map +1 -1
  87. package/dist/gs/io/fs/fs.js +26 -14
  88. package/dist/gs/io/fs/fs.js.map +1 -1
  89. package/dist/gs/io/fs/readdir.js +8 -4
  90. package/dist/gs/io/fs/readdir.js.map +1 -1
  91. package/dist/gs/io/fs/sub.js +8 -1
  92. package/dist/gs/io/fs/sub.js.map +1 -1
  93. package/dist/gs/io/io.d.ts +12 -6
  94. package/dist/gs/io/io.js +87 -42
  95. package/dist/gs/io/io.js.map +1 -1
  96. package/dist/gs/math/bits/index.d.ts +31 -5
  97. package/dist/gs/math/bits/index.js +29 -28
  98. package/dist/gs/math/bits/index.js.map +1 -1
  99. package/dist/gs/mime/index.d.ts +16 -0
  100. package/dist/gs/mime/index.js +315 -6
  101. package/dist/gs/mime/index.js.map +1 -1
  102. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  103. package/dist/gs/net/http/httptest/index.js +85 -6
  104. package/dist/gs/net/http/httptest/index.js.map +1 -1
  105. package/dist/gs/net/http/index.d.ts +303 -6
  106. package/dist/gs/net/http/index.js +1615 -58
  107. package/dist/gs/net/http/index.js.map +1 -1
  108. package/dist/gs/os/dir_unix.gs.js +1 -1
  109. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  110. package/dist/gs/os/error.gs.js +1 -1
  111. package/dist/gs/os/error.gs.js.map +1 -1
  112. package/dist/gs/os/exec.gs.d.ts +1 -0
  113. package/dist/gs/os/exec.gs.js +4 -8
  114. package/dist/gs/os/exec.gs.js.map +1 -1
  115. package/dist/gs/os/exec_posix.gs.js +1 -1
  116. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  117. package/dist/gs/os/index.d.ts +1 -1
  118. package/dist/gs/os/index.js +1 -1
  119. package/dist/gs/os/index.js.map +1 -1
  120. package/dist/gs/os/proc.gs.d.ts +4 -0
  121. package/dist/gs/os/proc.gs.js +12 -6
  122. package/dist/gs/os/proc.gs.js.map +1 -1
  123. package/dist/gs/os/root_js.gs.js +1 -1
  124. package/dist/gs/os/root_js.gs.js.map +1 -1
  125. package/dist/gs/os/types.gs.js +1 -1
  126. package/dist/gs/os/types.gs.js.map +1 -1
  127. package/dist/gs/os/types_js.gs.d.ts +6 -2
  128. package/dist/gs/os/types_js.gs.js +170 -9
  129. package/dist/gs/os/types_js.gs.js.map +1 -1
  130. package/dist/gs/os/types_unix.gs.js +1 -1
  131. package/dist/gs/os/types_unix.gs.js.map +1 -1
  132. package/dist/gs/path/path.js +11 -7
  133. package/dist/gs/path/path.js.map +1 -1
  134. package/dist/gs/reflect/index.d.ts +5 -4
  135. package/dist/gs/reflect/index.js +4 -3
  136. package/dist/gs/reflect/index.js.map +1 -1
  137. package/dist/gs/reflect/map.js +15 -0
  138. package/dist/gs/reflect/map.js.map +1 -1
  139. package/dist/gs/reflect/type.d.ts +26 -6
  140. package/dist/gs/reflect/type.js +1498 -279
  141. package/dist/gs/reflect/type.js.map +1 -1
  142. package/dist/gs/reflect/types.d.ts +14 -6
  143. package/dist/gs/reflect/types.js +35 -1
  144. package/dist/gs/reflect/types.js.map +1 -1
  145. package/dist/gs/reflect/value.d.ts +1 -0
  146. package/dist/gs/reflect/value.js +83 -41
  147. package/dist/gs/reflect/value.js.map +1 -1
  148. package/dist/gs/reflect/visiblefields.js +4 -140
  149. package/dist/gs/reflect/visiblefields.js.map +1 -1
  150. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  151. package/dist/gs/runtime/pprof/index.js +50 -30
  152. package/dist/gs/runtime/pprof/index.js.map +1 -1
  153. package/dist/gs/runtime/runtime.js +5 -4
  154. package/dist/gs/runtime/runtime.js.map +1 -1
  155. package/dist/gs/runtime/trace/index.js +5 -19
  156. package/dist/gs/runtime/trace/index.js.map +1 -1
  157. package/dist/gs/strconv/atoi.gs.js +1 -1
  158. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  159. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  160. package/dist/gs/strconv/complex.gs.js +148 -0
  161. package/dist/gs/strconv/complex.gs.js.map +1 -0
  162. package/dist/gs/strconv/index.d.ts +1 -0
  163. package/dist/gs/strconv/index.js +1 -0
  164. package/dist/gs/strconv/index.js.map +1 -1
  165. package/dist/gs/strings/builder.js +1 -1
  166. package/dist/gs/strings/reader.d.ts +1 -1
  167. package/dist/gs/strings/reader.js +11 -7
  168. package/dist/gs/strings/reader.js.map +1 -1
  169. package/dist/gs/strings/replace.js +15 -7
  170. package/dist/gs/strings/replace.js.map +1 -1
  171. package/dist/gs/strings/strings.d.ts +5 -0
  172. package/dist/gs/strings/strings.js +57 -5
  173. package/dist/gs/strings/strings.js.map +1 -1
  174. package/dist/gs/sync/atomic/type.gs.js +9 -9
  175. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  176. package/dist/gs/sync/atomic/value.gs.js +2 -2
  177. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  178. package/dist/gs/sync/sync.d.ts +2 -1
  179. package/dist/gs/sync/sync.js +37 -16
  180. package/dist/gs/sync/sync.js.map +1 -1
  181. package/dist/gs/syscall/env.js +22 -14
  182. package/dist/gs/syscall/env.js.map +1 -1
  183. package/dist/gs/syscall/js/index.js +9 -0
  184. package/dist/gs/syscall/js/index.js.map +1 -1
  185. package/dist/gs/testing/testing.js +59 -15
  186. package/dist/gs/testing/testing.js.map +1 -1
  187. package/dist/gs/time/time.d.ts +24 -1
  188. package/dist/gs/time/time.js +43 -3
  189. package/dist/gs/time/time.js.map +1 -1
  190. package/dist/gs/unique/index.js +7 -1
  191. package/dist/gs/unique/index.js.map +1 -1
  192. package/go.mod +3 -3
  193. package/go.sum +16 -0
  194. package/gs/builtin/builtin.ts +25 -2
  195. package/gs/builtin/runtime-contract.test.ts +260 -18
  196. package/gs/builtin/slice.ts +51 -4
  197. package/gs/builtin/type.ts +310 -63
  198. package/gs/builtin/varRef.ts +85 -2
  199. package/gs/bytes/buffer.gs.ts +1 -1
  200. package/gs/bytes/reader.gs.ts +1 -1
  201. package/gs/compress/zlib/index.test.ts +159 -1
  202. package/gs/compress/zlib/index.ts +164 -37
  203. package/gs/compress/zlib/meta.json +4 -1
  204. package/gs/compress/zlib/parity.json +51 -0
  205. package/gs/crypto/sha1/index.test.ts +19 -2
  206. package/gs/crypto/sha1/index.ts +3 -6
  207. package/gs/crypto/sha256/index.test.ts +14 -2
  208. package/gs/crypto/sha256/index.ts +3 -6
  209. package/gs/crypto/sha512/index.test.ts +17 -2
  210. package/gs/crypto/sha512/index.ts +3 -6
  211. package/gs/embed/index.test.ts +87 -0
  212. package/gs/embed/index.ts +229 -5
  213. package/gs/encoding/json/index.test.ts +360 -6
  214. package/gs/encoding/json/index.ts +679 -38
  215. package/gs/encoding/json/parity.json +81 -0
  216. package/gs/fmt/fmt.test.ts +41 -3
  217. package/gs/fmt/fmt.ts +40 -17
  218. package/gs/fmt/meta.json +6 -1
  219. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
  220. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
  221. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  222. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  223. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  224. package/gs/github.com/pkg/errors/errors.ts +54 -30
  225. package/gs/go/scanner/index.test.ts +39 -56
  226. package/gs/go/scanner/index.ts +33 -5
  227. package/gs/go/scanner/parity.json +27 -0
  228. package/gs/go/token/index.ts +22 -6
  229. package/gs/hash/index.test.ts +20 -33
  230. package/gs/hash/index.ts +28 -0
  231. package/gs/hash/parity.json +21 -0
  232. package/gs/internal/goarch/index.test.ts +32 -0
  233. package/gs/internal/goarch/index.ts +45 -13
  234. package/gs/internal/goarch/parity.json +144 -0
  235. package/gs/io/fs/fs.ts +26 -14
  236. package/gs/io/fs/readdir.test.ts +38 -0
  237. package/gs/io/fs/readdir.ts +8 -4
  238. package/gs/io/fs/sub.ts +8 -1
  239. package/gs/io/io.test.ts +77 -6
  240. package/gs/io/io.ts +115 -52
  241. package/gs/io/meta.json +7 -1
  242. package/gs/io/parity.json +162 -0
  243. package/gs/math/bits/index.test.ts +14 -1
  244. package/gs/math/bits/index.ts +75 -32
  245. package/gs/math/bits/parity.json +156 -0
  246. package/gs/mime/index.test.ts +90 -0
  247. package/gs/mime/index.ts +369 -6
  248. package/gs/mime/parity.json +36 -0
  249. package/gs/net/http/httptest/index.test.ts +98 -2
  250. package/gs/net/http/httptest/index.ts +101 -6
  251. package/gs/net/http/httptest/parity.json +15 -0
  252. package/gs/net/http/index.test.ts +797 -12
  253. package/gs/net/http/index.ts +1874 -136
  254. package/gs/net/http/meta.json +16 -1
  255. package/gs/net/http/parity.json +193 -0
  256. package/gs/os/dir_unix.gs.ts +1 -1
  257. package/gs/os/error.gs.ts +1 -1
  258. package/gs/os/exec.gs.ts +4 -8
  259. package/gs/os/exec_posix.gs.ts +1 -1
  260. package/gs/os/file_unix_js.test.ts +52 -0
  261. package/gs/os/index.test.ts +9 -0
  262. package/gs/os/index.ts +1 -0
  263. package/gs/os/meta.json +4 -0
  264. package/gs/os/parity.json +9 -0
  265. package/gs/os/proc.gs.ts +18 -5
  266. package/gs/os/proc.test.ts +26 -0
  267. package/gs/os/readdir.test.ts +56 -0
  268. package/gs/os/root_js.gs.ts +1 -1
  269. package/gs/os/types.gs.ts +1 -1
  270. package/gs/os/types_js.gs.ts +170 -9
  271. package/gs/os/types_unix.gs.ts +1 -1
  272. package/gs/path/path.ts +11 -7
  273. package/gs/reflect/deepequal.test.ts +10 -1
  274. package/gs/reflect/field.test.ts +37 -15
  275. package/gs/reflect/function-types.test.ts +518 -22
  276. package/gs/reflect/index.ts +8 -6
  277. package/gs/reflect/map.ts +20 -0
  278. package/gs/reflect/meta.json +6 -4
  279. package/gs/reflect/parity.json +234 -0
  280. package/gs/reflect/sliceat.test.ts +156 -0
  281. package/gs/reflect/structof.test.ts +401 -0
  282. package/gs/reflect/type.ts +1980 -365
  283. package/gs/reflect/typefor.test.ts +540 -10
  284. package/gs/reflect/types.ts +43 -18
  285. package/gs/reflect/value.ts +105 -45
  286. package/gs/reflect/visiblefields.ts +5 -168
  287. package/gs/runtime/parity.json +24 -0
  288. package/gs/runtime/pprof/index.test.ts +29 -7
  289. package/gs/runtime/pprof/index.ts +56 -30
  290. package/gs/runtime/pprof/parity.json +27 -0
  291. package/gs/runtime/runtime.test.ts +3 -1
  292. package/gs/runtime/runtime.ts +4 -3
  293. package/gs/runtime/trace/index.test.ts +5 -3
  294. package/gs/runtime/trace/index.ts +8 -20
  295. package/gs/runtime/trace/parity.json +36 -0
  296. package/gs/strconv/atoi.gs.ts +1 -1
  297. package/gs/strconv/complex.gs.ts +174 -0
  298. package/gs/strconv/complex.test.ts +65 -0
  299. package/gs/strconv/index.ts +1 -0
  300. package/gs/strconv/parity.json +120 -0
  301. package/gs/strings/builder.ts +1 -1
  302. package/gs/strings/meta.json +5 -2
  303. package/gs/strings/parity.json +186 -0
  304. package/gs/strings/reader.test.ts +2 -2
  305. package/gs/strings/reader.ts +11 -7
  306. package/gs/strings/replace.ts +15 -7
  307. package/gs/strings/strings.test.ts +22 -2
  308. package/gs/strings/strings.ts +64 -6
  309. package/gs/sync/atomic/type.gs.ts +9 -9
  310. package/gs/sync/atomic/value.gs.ts +2 -2
  311. package/gs/sync/meta.json +1 -0
  312. package/gs/sync/sync.test.ts +41 -1
  313. package/gs/sync/sync.ts +41 -16
  314. package/gs/syscall/env.ts +29 -14
  315. package/gs/syscall/js/index.test.ts +18 -0
  316. package/gs/syscall/js/index.ts +12 -0
  317. package/gs/testing/testing.test.ts +99 -3
  318. package/gs/testing/testing.ts +95 -24
  319. package/gs/time/parity.json +225 -0
  320. package/gs/time/time.test.ts +20 -2
  321. package/gs/time/time.ts +49 -7
  322. package/gs/unique/index.ts +7 -1
  323. package/package.json +4 -2
  324. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  325. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -814
  326. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  327. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -31
  328. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1233
  329. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
  330. /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
  }
@@ -401,8 +567,9 @@ export class Value {
401
567
 
402
568
  // Methods required by godoc.txt and used throughout the codebase
403
569
  public Int(): number {
404
- if (typeof this._value === 'number' && Number.isInteger(this._value)) {
405
- return this._value
570
+ const value = this.numericValue()
571
+ if (value !== null && Number.isInteger(value)) {
572
+ return value
406
573
  }
407
574
  throw new Error(
408
575
  'reflect: call of reflect.Value.Int on ' +
@@ -412,8 +579,9 @@ export class Value {
412
579
  }
413
580
 
414
581
  public Uint(): number {
415
- if (typeof this._value === 'number' && this._value >= 0) {
416
- return this._value
582
+ const value = this.numericValue()
583
+ if (value !== null && value >= 0) {
584
+ return value
417
585
  }
418
586
  throw new Error(
419
587
  'reflect: call of reflect.Value.Uint on ' +
@@ -423,8 +591,9 @@ export class Value {
423
591
  }
424
592
 
425
593
  public Float(): number {
426
- if (typeof this._value === 'number') {
427
- return this._value
594
+ const value = this.numericValue()
595
+ if (value !== null) {
596
+ return value
428
597
  }
429
598
  throw new Error(
430
599
  'reflect: call of reflect.Value.Float on ' +
@@ -444,6 +613,23 @@ export class Value {
444
613
  )
445
614
  }
446
615
 
616
+ private numericValue(): number | null {
617
+ if (typeof this._value === 'number') {
618
+ return this._value
619
+ }
620
+ if (
621
+ this._value !== null &&
622
+ typeof this._value === 'object' &&
623
+ typeof (this._value as { valueOf?: unknown }).valueOf === 'function'
624
+ ) {
625
+ const value = (this._value as { valueOf(): unknown }).valueOf()
626
+ if (typeof value === 'number') {
627
+ return value
628
+ }
629
+ }
630
+ return null
631
+ }
632
+
447
633
  public String(): string {
448
634
  if (typeof this._value === 'string') {
449
635
  return this._value
@@ -456,6 +642,10 @@ export class Value {
456
642
  }
457
643
 
458
644
  public Len(): number {
645
+ if (this.Kind() === Slice || this.Kind() === Array) {
646
+ return $.len(this._value as any)
647
+ }
648
+
459
649
  // Check for slice objects created by $.arrayToSlice
460
650
  if (
461
651
  this._value &&
@@ -519,8 +709,9 @@ export class Value {
519
709
  }
520
710
 
521
711
  public Index(i: number): Value {
522
- if (globalThis.Array.isArray(this._value)) {
523
- 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)
524
715
  }
525
716
  throw new Error(
526
717
  'reflect: call of reflect.Value.Index on ' +
@@ -576,6 +767,17 @@ export class Value {
576
767
  const elemType = this._type.Elem()
577
768
  return new Value(varRef.value, elemType, varRef)
578
769
  }
770
+ if (
771
+ this._type.Kind() === Ptr &&
772
+ this._value &&
773
+ typeof this._value === 'object' &&
774
+ '__goValue' in this._value &&
775
+ $.isVarRef((this._value as { __goValue: unknown }).__goValue)
776
+ ) {
777
+ const varRef = (this._value as { __goValue: $.VarRef<ReflectValue> })
778
+ .__goValue
779
+ return new Value(varRef.value, this._type.Elem(), varRef)
780
+ }
579
781
  // For interfaces, return the underlying value
580
782
  return new Value(this._value, this._type, this._parentVarRef)
581
783
  }
@@ -590,17 +792,18 @@ export class Value {
590
792
  }
591
793
 
592
794
  const field = this.Type().Field(i)
795
+ const fieldKey = structFieldStorageKey(this.Type(), i)
593
796
  if (!field) {
594
797
  throw new Error('reflect: struct field index out of range')
595
798
  }
596
799
 
597
800
  const parentObj = this._value as Record<string, any>
598
- let fieldVal = parentObj[field.Name]
801
+ let fieldVal = parentObj[fieldKey]
599
802
  if (fieldVal === undefined) {
600
803
  fieldVal = null
601
804
  }
602
805
  // Pass parent struct and field name so Set() can update the struct
603
- return new Value(fieldVal, field.Type, undefined, parentObj, field.Name)
806
+ return new Value(fieldVal, field.Type, undefined, parentObj, fieldKey)
604
807
  }
605
808
 
606
809
  public FieldByIndex(index: $.Slice<number>): Value {
@@ -639,6 +842,9 @@ export class Value {
639
842
  if (this._value === null || this._value === undefined) {
640
843
  return 0
641
844
  }
845
+ if ($.isOwnedPointerHandle(this._value)) {
846
+ return $.ownedPointerAddress(this._value)
847
+ }
642
848
  if ($.isVarRef(this._value)) {
643
849
  const address = this._value.__goAddress?.()
644
850
  if (address !== undefined) {
@@ -663,12 +869,26 @@ export class Value {
663
869
  return 0
664
870
  }
665
871
 
666
- public UnsafeAddr(): number | { value: Value } {
872
+ public UnsafeAddr(): number | $.OwnedPointerHandle<ReflectValue> {
667
873
  if (!this.CanAddr()) {
668
874
  throw new ValueError({ Kind: this.Kind(), Method: 'UnsafeAddr' })
669
875
  }
670
876
  if (this._parentStruct && this._fieldName) {
671
- 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>
672
892
  }
673
893
  return this.Pointer()
674
894
  }
@@ -704,6 +924,9 @@ export class Value {
704
924
  if (this._parentStruct && this._fieldName) {
705
925
  return new Value($.fieldRef(this._parentStruct, this._fieldName), ptrType)
706
926
  }
927
+ if (this._parentVarRef) {
928
+ return new Value(this._parentVarRef, ptrType)
929
+ }
707
930
  return new Value($.varRef(this._value), ptrType)
708
931
  }
709
932
 
@@ -717,23 +940,9 @@ export class Value {
717
940
  if (!this.CanSet()) {
718
941
  throw new Error('reflect: assign to invalid value')
719
942
  }
720
- // Interface types can accept any value
721
- if (this.Kind() === Interface) {
722
- this._value = x.value
723
- // Also update the parent VarRef if we were dereferenced from one
724
- if (this._parentVarRef) {
725
- this._parentVarRef.value = x.value
726
- }
727
- // Also update the parent struct field if this is a struct field
728
- if (this._parentStruct && this._fieldName) {
729
- this._parentStruct[this._fieldName] = x.value
730
- }
731
- return
732
- }
733
- // For other types, check if types are compatible (simplified check)
734
943
  const thisType = this.Type()
735
944
  const xType = x.Type()
736
- if (thisType.Kind() !== xType.Kind()) {
945
+ if (!xType.AssignableTo(thisType)) {
737
946
  throw new Error('reflect: assign to wrong type')
738
947
  }
739
948
  this._value = x.value
@@ -768,22 +977,36 @@ export class Value {
768
977
  if (typeof method !== 'function') {
769
978
  return new Value()
770
979
  }
771
- 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)
772
986
  }
773
987
 
774
- public Call(inArgs: $.Slice<Value>): $.Slice<Value> {
988
+ public async Call(inArgs: $.Slice<Value>): Promise<$.Slice<Value>> {
775
989
  if (this.Kind() !== Func || typeof this._value !== 'function') {
776
990
  throw new ValueError({ Kind: this.Kind(), Method: 'Call' })
777
991
  }
778
- const args = $.asArray(inArgs).map((arg) => arg.Interface())
779
- const result = this._value(...args) as ReflectValue | ReflectValue[]
780
- if (globalThis.Array.isArray(result)) {
781
- return $.arrayToSlice(result.map((value) => ValueOf(value)))
782
- }
783
- if (result === undefined) {
784
- 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' })
785
1003
  }
786
- return $.arrayToSlice([ValueOf(result)])
1004
+ return await callReflectFunction(
1005
+ this._value as (...args: unknown[]) => unknown,
1006
+ this._type,
1007
+ inArgs,
1008
+ 'CallSlice',
1009
+ )
787
1010
  }
788
1011
 
789
1012
  public IsZero(): boolean {
@@ -1118,10 +1341,7 @@ export class Value {
1118
1341
  public Cap(): number {
1119
1342
  const k = this.Kind()
1120
1343
  if (k === Slice || k === Array) {
1121
- if (globalThis.Array.isArray(this._value)) {
1122
- return this._value.length
1123
- }
1124
- return 0
1344
+ return $.cap(this._value as any)
1125
1345
  }
1126
1346
  if (k === Chan) {
1127
1347
  return 0 // Simplified
@@ -1211,6 +1431,7 @@ export class BasicType implements Type {
1211
1431
  private _name: string,
1212
1432
  private _size: number = 8,
1213
1433
  private _typeName: string = '',
1434
+ private _methods: $.MethodSignature[] = [],
1214
1435
  ) {}
1215
1436
 
1216
1437
  public String(): string {
@@ -1221,6 +1442,10 @@ export class BasicType implements Type {
1221
1442
  return this._kind
1222
1443
  }
1223
1444
 
1445
+ public underlyingName(): string {
1446
+ return Kind_String(this._kind)
1447
+ }
1448
+
1224
1449
  public Comparable(): boolean {
1225
1450
  return this._kind !== Func && this._kind !== Map && this._kind !== Slice
1226
1451
  }
@@ -1237,6 +1462,26 @@ export class BasicType implements Type {
1237
1462
  return 0
1238
1463
  }
1239
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
+
1240
1485
  public PkgPath(): string {
1241
1486
  if (this._typeName) {
1242
1487
  const dotIndex = this._typeName.lastIndexOf('.')
@@ -1284,7 +1529,7 @@ export class BasicType implements Type {
1284
1529
  if (u.Kind() !== Interface) {
1285
1530
  throw new Error('reflect: non-interface type passed to Type.Implements')
1286
1531
  }
1287
- return false
1532
+ return typeImplementsInterface(this, u)
1288
1533
  }
1289
1534
 
1290
1535
  public AssignableTo(u: Type | null): boolean {
@@ -1355,10 +1600,18 @@ export class BasicType implements Type {
1355
1600
  }
1356
1601
 
1357
1602
  public NumMethod(): number {
1358
- return 0
1603
+ return typeMethods(this).length
1359
1604
  }
1360
- public MethodByName(_name: string): [Method, boolean] {
1361
- 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)
1362
1615
  }
1363
1616
 
1364
1617
  public Len(): number {
@@ -1432,6 +1685,26 @@ class SliceType implements Type {
1432
1685
  return 0
1433
1686
  }
1434
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
+
1435
1708
  public PkgPath(): string {
1436
1709
  return ''
1437
1710
  }
@@ -1466,7 +1739,7 @@ class SliceType implements Type {
1466
1739
  if (u.Kind() !== Interface) {
1467
1740
  throw new Error('reflect: non-interface type passed to Type.Implements')
1468
1741
  }
1469
- return false
1742
+ return typeImplementsInterface(this, u)
1470
1743
  }
1471
1744
 
1472
1745
  public AssignableTo(u: Type | null): boolean {
@@ -1532,6 +1805,26 @@ class ArrayType implements Type {
1532
1805
  return 0
1533
1806
  }
1534
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
+
1535
1828
  public Len(): number {
1536
1829
  return this._len
1537
1830
  }
@@ -1570,7 +1863,7 @@ class ArrayType implements Type {
1570
1863
  if (u.Kind() !== Interface) {
1571
1864
  throw new Error('reflect: non-interface type passed to Type.Implements')
1572
1865
  }
1573
- return false
1866
+ return typeImplementsInterface(this, u)
1574
1867
  }
1575
1868
 
1576
1869
  public AssignableTo(u: Type | null): boolean {
@@ -1607,7 +1900,10 @@ class ArrayType implements Type {
1607
1900
 
1608
1901
  // Pointer type implementation
1609
1902
  class PointerType implements Type {
1610
- constructor(private _elemType: Type) {}
1903
+ constructor(
1904
+ private _elemType: Type,
1905
+ private _methods: $.MethodSignature[] = [],
1906
+ ) {}
1611
1907
 
1612
1908
  public String(): string {
1613
1909
  return '*' + this._elemType.String()
@@ -1633,6 +1929,26 @@ class PointerType implements Type {
1633
1929
  return 0
1634
1930
  }
1635
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
+
1636
1952
  public PkgPath(): string {
1637
1953
  return ''
1638
1954
  }
@@ -1667,9 +1983,7 @@ class PointerType implements Type {
1667
1983
  if (u.Kind() !== Interface) {
1668
1984
  throw new Error('reflect: non-interface type passed to Type.Implements')
1669
1985
  }
1670
- // For pointer types, check if the element type implements the interface
1671
- const elemTypeName = this._elemType.String()
1672
- return typeImplementsInterface(elemTypeName, u)
1986
+ return typeImplementsInterface(this, u)
1673
1987
  }
1674
1988
 
1675
1989
  public AssignableTo(u: Type | null): boolean {
@@ -1697,10 +2011,18 @@ class PointerType implements Type {
1697
2011
  }
1698
2012
 
1699
2013
  public NumMethod(): number {
1700
- return 0
2014
+ return typeMethods(this).length
1701
2015
  }
1702
2016
  public MethodByName(name: string): [Method, boolean] {
1703
- 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)
1704
2026
  }
1705
2027
 
1706
2028
  public Len(): number {
@@ -1713,10 +2035,54 @@ class PointerType implements Type {
1713
2035
  }
1714
2036
 
1715
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
+
1716
2047
  class FunctionType implements Type {
1717
- 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
+ }
1718
2081
 
1719
2082
  public String(): string {
2083
+ if (this._name !== '') {
2084
+ return this._name
2085
+ }
1720
2086
  return this._signature
1721
2087
  }
1722
2088
 
@@ -1740,12 +2106,54 @@ class FunctionType implements Type {
1740
2106
  return 0
1741
2107
  }
1742
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
+
1743
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
+ }
1744
2146
  return ''
1745
2147
  }
1746
2148
 
1747
2149
  public Name(): string {
1748
- // 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
+ }
1749
2157
  return ''
1750
2158
  }
1751
2159
 
@@ -1774,7 +2182,7 @@ class FunctionType implements Type {
1774
2182
  if (u.Kind() !== Interface) {
1775
2183
  throw new Error('reflect: non-interface type passed to Type.Implements')
1776
2184
  }
1777
- return false
2185
+ return typeImplementsInterface(this, u)
1778
2186
  }
1779
2187
 
1780
2188
  public AssignableTo(u: Type | null): boolean {
@@ -1798,10 +2206,29 @@ class FunctionType implements Type {
1798
2206
  }
1799
2207
 
1800
2208
  public NumMethod(): number {
1801
- return 0
2209
+ return typeMethods(this).length
1802
2210
  }
1803
- public MethodByName(_name: string): [Method, boolean] {
1804
- 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
1805
2232
  }
1806
2233
 
1807
2234
  public Len(): number {
@@ -1813,59 +2240,316 @@ class FunctionType implements Type {
1813
2240
  }
1814
2241
  }
1815
2242
 
1816
- // Map type implementation
1817
- class MapType implements Type {
1818
- constructor(
1819
- private _keyType: Type,
1820
- private _elemType: Type,
1821
- ) {}
1822
-
1823
- public String(): string {
1824
- 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(', ')})`
1825
2263
  }
2264
+ return signature
2265
+ }
1826
2266
 
1827
- public Kind(): Kind {
1828
- return Map
1829
- }
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
+ }
1830
2278
 
1831
- public Comparable(): boolean {
1832
- return false
1833
- }
2279
+ type ReflectCallOp = 'Call' | 'CallSlice'
1834
2280
 
1835
- public Size(): number {
1836
- 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)
1837
2288
  }
1838
-
1839
- public Elem(): Type {
1840
- 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
+ )
1841
2294
  }
1842
-
1843
- public NumField(): number {
1844
- return 0
2295
+ const fixedCount = fnType.NumIn() - 1
2296
+ if (args.length < fixedCount) {
2297
+ throw new Error('reflect: Call with too few input arguments')
1845
2298
  }
1846
-
1847
- public Key(): Type {
1848
- 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))
1849
2302
  }
1850
-
1851
- public PkgPath(): string {
1852
- 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
+ }
1853
2315
  }
2316
+ rawArgs.push($.arrayToSlice(variadicValues.map((value) => value.Interface())))
2317
+ return rawArgs
2318
+ }
1854
2319
 
1855
- public Name(): string {
1856
- // Map types are unnamed composite types
1857
- return ''
2320
+ function reflectCallSliceRawArgs(fnType: Type, args: Value[]): unknown[] {
2321
+ if (!fnType.IsVariadic()) {
2322
+ throw new Error('reflect: CallSlice of non-variadic function')
1858
2323
  }
1859
-
1860
- public Field(_i: number): StructField {
1861
- 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')
1862
2327
  }
1863
-
1864
- public FieldByName(name: string): [StructField, boolean] {
1865
- return typeFieldByName(this, name)
2328
+ if (args.length > expected) {
2329
+ throw new Error('reflect: CallSlice with too many input arguments')
1866
2330
  }
2331
+ return args.map((arg, index) =>
2332
+ reflectCallValueInterface('CallSlice', arg, fnType.In(index), index),
2333
+ )
2334
+ }
1867
2335
 
1868
- public FieldByNameFunc(
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`)
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
+ }
2352
+
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
+ )
2359
+ }
2360
+ }
2361
+
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
+ )
2372
+ }
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(
1869
2553
  match: (name: string) => boolean,
1870
2554
  ): [StructField, boolean] {
1871
2555
  return typeFieldByNameFunc(this, match)
@@ -1878,7 +2562,7 @@ class MapType implements Type {
1878
2562
  if (u.Kind() !== Interface) {
1879
2563
  throw new Error('reflect: non-interface type passed to Type.Implements')
1880
2564
  }
1881
- return false
2565
+ return typeImplementsInterface(this, u)
1882
2566
  }
1883
2567
 
1884
2568
  public AssignableTo(u: Type | null): boolean {
@@ -1918,61 +2602,174 @@ class MapType implements Type {
1918
2602
  }
1919
2603
 
1920
2604
  // Struct type implementation
1921
- /**
1922
- * Helper function to check if a type's method set contains all methods
1923
- * required by an interface.
1924
- *
1925
- * @param typeName The name of the type to check (e.g., "main.MyType")
1926
- * @param interfaceType The interface type that must be implemented
1927
- * @returns True if the type implements the interface, false otherwise
1928
- */
1929
- function typeImplementsInterface(
1930
- typeName: string,
1931
- interfaceType: Type,
1932
- ): boolean {
1933
- // Get the interface name and look it up in the type registry
1934
- const interfaceName =
1935
- interfaceType instanceof InterfaceType ?
1936
- interfaceType.registeredName() || interfaceType.String()
1937
- : interfaceType.String()
1938
- const interfaceTypeInfo = builtinGetTypeByName(interfaceName)
1939
-
1940
- if (!interfaceTypeInfo || !isInterfaceTypeInfo(interfaceTypeInfo)) {
1941
- 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')
1942
2608
  }
2609
+ const requiredMethods = typeMethods(interfaceType)
2610
+ if (requiredMethods.length === 0) {
2611
+ return true
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
+ }
1943
2623
 
1944
- // Get the type info for the struct/type
1945
- 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
+ }
1946
2633
 
1947
- if (!typeInfo || !isStructTypeInfo(typeInfo)) {
2634
+ function methodArgListIdentical(
2635
+ actual: $.MethodArg[],
2636
+ required: $.MethodArg[],
2637
+ ): boolean {
2638
+ if (actual.length !== required.length) {
1948
2639
  return false
1949
2640
  }
2641
+ return actual.every(
2642
+ (arg, index) =>
2643
+ methodArgIdentityKey(arg) === methodArgIdentityKey(required[index]),
2644
+ )
2645
+ }
1950
2646
 
1951
- // Check if the type has all required methods
1952
- const requiredMethods = interfaceTypeInfo.methods || []
1953
- const typeMethods = typeInfo.methods || []
2647
+ function methodArgIdentityKey(arg: $.MethodArg): string {
2648
+ return typeInfoIdentityKey(arg.type, new Set())
2649
+ }
1954
2650
 
1955
- // For each required method, check if the type has a matching method
1956
- for (const requiredMethod of requiredMethods) {
1957
- 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
+ }
1958
2656
 
1959
- if (!typeMethod) {
1960
- 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
1961
2672
  }
1962
-
1963
- // Check if method signatures match (simplified - just check counts)
1964
- if (typeMethod.args.length !== requiredMethod.args.length) {
1965
- return false
2673
+ if (
2674
+ methodSignatureIdentityKey(merged[existingIndex]) !==
2675
+ methodSignatureIdentityKey(method)
2676
+ ) {
2677
+ merged[existingIndex] = method
1966
2678
  }
2679
+ }
2680
+ return merged.sort((left, right) => left.name.localeCompare(right.name))
2681
+ }
1967
2682
 
1968
- if (typeMethod.returns.length !== requiredMethod.returns.length) {
1969
- 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}`
1970
2691
  }
1971
-
1972
- // 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'
1973
2772
  }
1974
-
1975
- return true
1976
2773
  }
1977
2774
 
1978
2775
  function typeFieldByName(t: Type, name: string): [StructField, boolean] {
@@ -1986,8 +2783,7 @@ function typeFieldByNameFunc(
1986
2783
  if (t.Kind() !== Struct) {
1987
2784
  throw new Error('reflect: FieldByName of non-struct type')
1988
2785
  }
1989
- for (let i = 0; i < t.NumField(); i++) {
1990
- const field = t.Field(i)
2786
+ for (const field of visibleStructFields(t)) {
1991
2787
  if (match(field.Name)) {
1992
2788
  return [field, true]
1993
2789
  }
@@ -1995,6 +2791,59 @@ function typeFieldByNameFunc(
1995
2791
  return [new StructField(), false]
1996
2792
  }
1997
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
+
1998
2847
  function zeroMethod(): Method {
1999
2848
  return {
2000
2849
  Name: '',
@@ -2007,17 +2856,65 @@ function zeroMethod(): Method {
2007
2856
  function methodFromSignature(
2008
2857
  signature: $.MethodSignature,
2009
2858
  index: number,
2859
+ receiver: Type,
2010
2860
  ): Method {
2011
2861
  return {
2012
2862
  Name: signature.name,
2013
- Type: new FunctionType('func'),
2863
+ Type: methodTypeFromSignature(
2864
+ signature,
2865
+ receiver,
2866
+ receiver.Kind() !== Interface,
2867
+ ),
2014
2868
  Func: () => undefined,
2015
2869
  Index: index,
2016
2870
  }
2017
2871
  }
2018
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
+
2019
2892
  function typeMethods(t: Type): $.MethodSignature[] {
2020
- 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
+ }
2021
2918
  if (!typeInfo) {
2022
2919
  return []
2023
2920
  }
@@ -2027,30 +2924,119 @@ function typeMethods(t: Type): $.MethodSignature[] {
2027
2924
  return []
2028
2925
  }
2029
2926
 
2030
- function typeMethodByName(t: Type, name: string): [Method, boolean] {
2927
+ function methodSignatureByName(
2928
+ t: Type,
2929
+ name: string,
2930
+ ): [$.MethodSignature | undefined, number] {
2031
2931
  const methods = typeMethods(t)
2032
2932
  const index = methods.findIndex((method) => method.name === name)
2033
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) {
2034
2942
  return [zeroMethod(), false]
2035
2943
  }
2036
- return [methodFromSignature(methods[index], index), true]
2944
+ return [methodFromSignature(signature, index, t), true]
2037
2945
  }
2038
2946
 
2039
2947
  function typeAssignableTo(t: Type, u: Type | null): boolean {
2040
2948
  if (u === null) {
2041
2949
  return false
2042
2950
  }
2043
- 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)
2044
3028
  }
2045
3029
 
2046
3030
  class StructType implements Type {
2047
3031
  constructor(
2048
3032
  private _name: string,
2049
- private _fields: Array<{ name: string; type: Type; tag?: string }> = [],
3033
+ private _fields: StructFieldDescriptor[] = [],
3034
+ private _pkgPath = '',
3035
+ private _string = _name,
2050
3036
  ) {}
2051
3037
 
2052
3038
  public String(): string {
2053
- return this._name
3039
+ return this._string
2054
3040
  }
2055
3041
 
2056
3042
  public Kind(): Kind {
@@ -2062,8 +3048,7 @@ class StructType implements Type {
2062
3048
  }
2063
3049
 
2064
3050
  public Size(): number {
2065
- // Struct size is implementation-defined, we'll use a reasonable default
2066
- return this._fields.reduce((sum, field) => sum + field.type.Size(), 0)
3051
+ return structDescriptorSize(this._fields)
2067
3052
  }
2068
3053
 
2069
3054
  public Elem(): Type {
@@ -2074,7 +3059,33 @@ class StructType implements Type {
2074
3059
  return this._fields.length
2075
3060
  }
2076
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
+
2077
3082
  public PkgPath(): string {
3083
+ if (this._pkgPath !== '') {
3084
+ return this._pkgPath
3085
+ }
3086
+ if (this._name === '') {
3087
+ return ''
3088
+ }
2078
3089
  // Extract package path from full type name (e.g., "main.Person" -> "main")
2079
3090
  const dotIndex = this._name.lastIndexOf('.')
2080
3091
  if (dotIndex > 0) {
@@ -2084,6 +3095,9 @@ class StructType implements Type {
2084
3095
  }
2085
3096
 
2086
3097
  public Name(): string {
3098
+ if (this._name === '') {
3099
+ return ''
3100
+ }
2087
3101
  // Extract type name from full type name (e.g., "main.Person" -> "Person")
2088
3102
  const dotIndex = this._name.lastIndexOf('.')
2089
3103
  if (dotIndex >= 0) {
@@ -2101,13 +3115,68 @@ class StructType implements Type {
2101
3115
  const f = this._fields[i]
2102
3116
  return new StructField({
2103
3117
  Name: f.name,
2104
- PkgPath: '',
3118
+ PkgPath: f.pkgPath,
2105
3119
  Type: f.type,
2106
3120
  Tag: f.tag ? new StructTag(f.tag) : undefined,
2107
- Index: [i],
3121
+ Offset: f.offset,
3122
+ Index: [...f.index],
3123
+ Anonymous: f.anonymous,
2108
3124
  })
2109
3125
  }
2110
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
+
2111
3180
  public FieldByName(name: string): [StructField, boolean] {
2112
3181
  return typeFieldByName(this, name)
2113
3182
  }
@@ -2129,7 +3198,7 @@ class StructType implements Type {
2129
3198
  if (u.Kind() !== Interface) {
2130
3199
  throw new Error('reflect: non-interface type passed to Type.Implements')
2131
3200
  }
2132
- return typeImplementsInterface(this._name, u)
3201
+ return typeImplementsInterface(this, u)
2133
3202
  }
2134
3203
 
2135
3204
  public AssignableTo(u: Type | null): boolean {
@@ -2170,82 +3239,42 @@ class StructType implements Type {
2170
3239
  throw new Error('reflect: call of reflect.Type.Bits on struct Type')
2171
3240
  }
2172
3241
 
2173
- static createTypeFromFieldInfo(ti: any): Type {
3242
+ static createTypeFromFieldInfo(ti: any, seen = new Set<string>()): Type {
2174
3243
  if (typeof ti === 'string') {
2175
- switch (ti) {
2176
- case 'string':
2177
- return new BasicType(String, ti, 16)
2178
- case 'int':
2179
- case 'int32':
2180
- case 'int64':
2181
- case 'number':
2182
- return new BasicType(Int, ti === 'number' ? 'int' : ti, 8)
2183
- case 'bool':
2184
- case 'boolean':
2185
- return new BasicType(Bool, 'bool', 1)
2186
- case 'float64':
2187
- return new BasicType(Float64, ti, 8)
2188
- case 'complex64':
2189
- return new BasicType(Complex64, ti, 8)
2190
- case 'complex128':
2191
- return new BasicType(Complex128, ti, 16)
2192
- case 'uint':
2193
- case 'uint32':
2194
- case 'uint64':
2195
- return new BasicType(Uint, ti, 8)
2196
- default:
2197
- return new BasicType(Invalid, ti, 8)
2198
- }
3244
+ return basicTypeFromName(ti === 'number' ? 'int' : ti)
2199
3245
  } else if (ti && ti.kind) {
2200
3246
  // Handle TypeInfo objects from the builtin type system
2201
3247
  const name = ti.name || 'unknown'
2202
3248
  const typeName = ti.typeName || ''
2203
3249
  switch (ti.kind) {
2204
3250
  case 'basic':
2205
- // Map TypeScript type names to Go type names
2206
- switch (name) {
2207
- case 'string':
2208
- return new BasicType(String, 'string', 16, typeName)
2209
- case 'number':
2210
- case 'int':
2211
- case 'int32':
2212
- case 'int64':
2213
- return new BasicType(
2214
- Int,
2215
- name === 'number' ? 'int' : name,
2216
- 8,
2217
- typeName,
2218
- )
2219
- case 'boolean':
2220
- case 'bool':
2221
- return new BasicType(Bool, 'bool', 1, typeName)
2222
- case 'float64':
2223
- return new BasicType(Float64, 'float64', 8, typeName)
2224
- case 'complex64':
2225
- return new BasicType(Complex64, 'complex64', 8, typeName)
2226
- case 'complex128':
2227
- return new BasicType(Complex128, 'complex128', 16, typeName)
2228
- default:
2229
- return new BasicType(Invalid, name, 8, typeName)
2230
- }
3251
+ return basicTypeFromName(name === 'number' ? 'int' : name, typeName)
2231
3252
  case 'slice':
2232
3253
  if (ti.elemType) {
2233
3254
  return new SliceType(
2234
- StructType.createTypeFromFieldInfo(ti.elemType),
3255
+ StructType.createTypeFromFieldInfo(ti.elemType, seen),
2235
3256
  )
2236
3257
  }
2237
3258
  return new SliceType(new BasicType(Invalid, 'unknown', 8))
2238
3259
  case 'pointer':
2239
3260
  if (ti.elemType) {
2240
3261
  return new PointerType(
2241
- StructType.createTypeFromFieldInfo(ti.elemType),
3262
+ StructType.createTypeFromFieldInfo(ti.elemType, seen),
2242
3263
  )
2243
3264
  }
2244
3265
  return new PointerType(new BasicType(Invalid, 'unknown', 8))
2245
3266
  case 'interface':
2246
- return new InterfaceType(name)
2247
- case 'struct':
2248
- 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
+ }
2249
3278
  default:
2250
3279
  return new BasicType(Invalid, name, 8)
2251
3280
  }
@@ -2254,20 +3283,64 @@ class StructType implements Type {
2254
3283
  }
2255
3284
  }
2256
3285
 
3286
+ function basicTypeFromName(name: string, typeName = ''): BasicType {
3287
+ switch (name) {
3288
+ case 'string':
3289
+ return new BasicType(String, 'string', 16, typeName)
3290
+ case 'bool':
3291
+ case 'boolean':
3292
+ return new BasicType(Bool, 'bool', 1, typeName)
3293
+ case 'int':
3294
+ return new BasicType(Int, 'int', 8, typeName)
3295
+ case 'int8':
3296
+ return new BasicType(Int8, 'int8', 1, typeName)
3297
+ case 'int16':
3298
+ return new BasicType(Int16, 'int16', 2, typeName)
3299
+ case 'int32':
3300
+ return new BasicType(Int32, 'int32', 4, typeName)
3301
+ case 'int64':
3302
+ return new BasicType(Int64, 'int64', 8, typeName)
3303
+ case 'uint':
3304
+ return new BasicType(Uint, 'uint', 8, typeName)
3305
+ case 'uint8':
3306
+ case 'byte':
3307
+ return new BasicType(Uint8, name, 1, typeName)
3308
+ case 'uint16':
3309
+ return new BasicType(Uint16, 'uint16', 2, typeName)
3310
+ case 'uint32':
3311
+ return new BasicType(Uint32, 'uint32', 4, typeName)
3312
+ case 'uint64':
3313
+ return new BasicType(Uint64, 'uint64', 8, typeName)
3314
+ case 'uintptr':
3315
+ return new BasicType(Uintptr, 'uintptr', 8, typeName)
3316
+ case 'float32':
3317
+ return new BasicType(Float32, 'float32', 4, typeName)
3318
+ case 'float64':
3319
+ return new BasicType(Float64, 'float64', 8, typeName)
3320
+ case 'complex64':
3321
+ return new BasicType(Complex64, 'complex64', 8, typeName)
3322
+ case 'complex128':
3323
+ return new BasicType(Complex128, 'complex128', 16, typeName)
3324
+ default:
3325
+ return new BasicType(Invalid, name, 8, typeName)
3326
+ }
3327
+ }
3328
+
2257
3329
  function structFieldsFromTypeInfo(
2258
3330
  ti: $.StructTypeInfo,
2259
- ): Array<{ name: string; type: Type; tag?: string }> {
2260
- return Object.entries(ti.fields || {}).map(([name, fieldInfo]) => {
2261
- if (isStructFieldInfo(fieldInfo)) {
2262
- return {
2263
- name: fieldInfo.name ?? name,
2264
- type: typeFromTypeInfo(fieldInfo.type),
2265
- tag: fieldInfo.tag,
2266
- }
2267
- }
3331
+ seen = new Set<string>(),
3332
+ ): StructFieldDescriptor[] {
3333
+ return (ti.fields || []).map((fieldInfo, index) => {
2268
3334
  return {
2269
- name,
2270
- 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 ?? '') === '',
2271
3344
  }
2272
3345
  })
2273
3346
  }
@@ -2313,6 +3386,26 @@ class ChannelType implements Type {
2313
3386
  return 0
2314
3387
  }
2315
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
+
2316
3409
  public PkgPath(): string {
2317
3410
  return ''
2318
3411
  }
@@ -2347,7 +3440,7 @@ class ChannelType implements Type {
2347
3440
  if (u.Kind() !== Interface) {
2348
3441
  throw new Error('reflect: non-interface type passed to Type.Implements')
2349
3442
  }
2350
- return false
3443
+ return typeImplementsInterface(this, u)
2351
3444
  }
2352
3445
 
2353
3446
  public AssignableTo(u: Type | null): boolean {
@@ -2395,6 +3488,7 @@ class InterfaceType implements Type {
2395
3488
  constructor(
2396
3489
  private _name: string = 'interface{}',
2397
3490
  private _registeredName?: string,
3491
+ private _methods: $.MethodSignature[] = [],
2398
3492
  ) {}
2399
3493
 
2400
3494
  public String(): string {
@@ -2421,6 +3515,26 @@ class InterfaceType implements Type {
2421
3515
  return 0
2422
3516
  }
2423
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
+
2424
3538
  public PkgPath(): string {
2425
3539
  if (this._name === 'interface{}' || this._name.startsWith('interface {')) {
2426
3540
  return ''
@@ -2461,8 +3575,14 @@ class InterfaceType implements Type {
2461
3575
  throw new Error('reflect: Key of non-map type')
2462
3576
  }
2463
3577
 
2464
- public Implements(_u: Type | null): boolean {
2465
- 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)
2466
3586
  }
2467
3587
 
2468
3588
  public AssignableTo(u: Type | null): boolean {
@@ -2510,6 +3630,10 @@ class InterfaceType implements Type {
2510
3630
  public registeredName(): string | undefined {
2511
3631
  return this._registeredName
2512
3632
  }
3633
+
3634
+ public methodSignatures(): $.MethodSignature[] {
3635
+ return this._methods
3636
+ }
2513
3637
  }
2514
3638
 
2515
3639
  function getTypeOf(value: ReflectValue): Type {
@@ -2557,24 +3681,20 @@ function getTypeOf(value: ReflectValue): Type {
2557
3681
  typeInfo.params &&
2558
3682
  typeInfo.results
2559
3683
  ) {
3684
+ if (funcWithMeta.__goTypeName && !typeInfo.name) {
3685
+ return functionTypeFromInfo({
3686
+ ...typeInfo,
3687
+ name: funcWithMeta.__goTypeName,
3688
+ })
3689
+ }
2560
3690
  return functionTypeFromInfo(typeInfo)
2561
3691
  }
2562
3692
  }
2563
3693
 
2564
3694
  // Then check for __goTypeName which indicates a typed function
2565
3695
  if (funcWithMeta.__goTypeName) {
2566
- // This is a typed Go function - try to reconstruct the signature
2567
3696
  const typeName = funcWithMeta.__goTypeName
2568
-
2569
- // For known Go function types, construct proper signatures
2570
- if (typeName === 'Greeter') {
2571
- return new FunctionType('func(string) string')
2572
- } else if (typeName === 'Adder') {
2573
- return new FunctionType('func(int, int) int')
2574
- }
2575
-
2576
- // Generic fallback for typed functions
2577
- return new FunctionType(`func`) // Could be enhanced with parameter parsing
3697
+ return new FunctionType({ name: typeName })
2578
3698
  }
2579
3699
 
2580
3700
  // For untyped functions, try to parse the signature
@@ -2614,6 +3734,15 @@ function getTypeOf(value: ReflectValue): Type {
2614
3734
  return new PointerType(elemType)
2615
3735
  }
2616
3736
 
3737
+ if (
3738
+ '__goTypeInfo' in value &&
3739
+ (value as { __goTypeInfo?: $.TypeInfo | string }).__goTypeInfo
3740
+ ) {
3741
+ return typeFromTypeInfo(
3742
+ (value as { __goTypeInfo: $.TypeInfo | string }).__goTypeInfo,
3743
+ )
3744
+ }
3745
+
2617
3746
  if (
2618
3747
  'real' in value &&
2619
3748
  'imag' in value &&
@@ -2699,6 +3828,19 @@ function getTypeOf(value: ReflectValue): Type {
2699
3828
  }
2700
3829
 
2701
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
+
2702
3844
  if (
2703
3845
  value &&
2704
3846
  typeof value === 'object' &&
@@ -2706,34 +3848,19 @@ function getTypeOf(value: ReflectValue): Type {
2706
3848
  '__typeInfo' in value.constructor
2707
3849
  ) {
2708
3850
  const typeInfo = (
2709
- value.constructor as { __typeInfo?: { name?: string } }
3851
+ value.constructor as { __typeInfo?: $.StructTypeInfo }
2710
3852
  ).__typeInfo
2711
- if (typeInfo && typeInfo.name) {
2712
- const typeName =
2713
- typeInfo.name.includes('.') ?
2714
- typeInfo.name
2715
- : `main.${typeInfo.name}`
2716
- const regTypeInfo = builtinGetTypeByName(typeName)
2717
- let fields: Array<{ name: string; type: Type; tag?: string }> = []
2718
- if (regTypeInfo && isStructTypeInfo(regTypeInfo)) {
2719
- fields = Object.entries(regTypeInfo.fields || {}).map(
2720
- ([name, fieldInfo]) => {
2721
- // Check if fieldInfo is a StructFieldInfo with type and tag
2722
- if (isStructFieldInfo(fieldInfo)) {
2723
- return {
2724
- name: fieldInfo.name ?? name,
2725
- type: StructType.createTypeFromFieldInfo(fieldInfo.type),
2726
- tag: fieldInfo.tag,
2727
- }
2728
- }
2729
- // Otherwise it's just the type info directly (backwards compatible)
2730
- return {
2731
- name,
2732
- type: StructType.createTypeFromFieldInfo(fieldInfo),
2733
- }
2734
- },
2735
- )
3853
+ if (typeInfo && isStructTypeInfo(typeInfo)) {
3854
+ const name = typeInfo.name ?? ''
3855
+ if (name === '') {
3856
+ return new StructType('', structFieldsFromTypeInfo(typeInfo))
2736
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)
2737
3864
  return new StructType(typeName, fields)
2738
3865
  }
2739
3866
  }
@@ -2797,20 +3924,168 @@ export function ChanOf(dir: ChanDir, t: Type): Type {
2797
3924
  return internType(new ChannelType(t, dir))
2798
3925
  }
2799
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
+
2800
4070
  export function TypeFor(typeArgs?: $.GenericTypeArgs): Type {
2801
4071
  const descriptor = typeArgs?.T
4072
+ const methodSignatures = genericMethodSignatures(descriptor)
2802
4073
  if (descriptor?.type) {
2803
- return internType(typeFromTypeInfo(descriptor.type))
2804
- }
2805
- if (descriptor?.methods) {
2806
- const methods = Object.keys(descriptor.methods)
2807
- if (methods.length !== 0) {
2808
- return internType(
2809
- new InterfaceType(
2810
- `interface { ${methods.map((method) => method + '()').join('; ')} }`,
2811
- ),
2812
- )
2813
- }
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
+ )
2814
4089
  }
2815
4090
  if (descriptor?.zero) {
2816
4091
  return internType(getTypeOf(descriptor.zero()))
@@ -2818,113 +4093,475 @@ export function TypeFor(typeArgs?: $.GenericTypeArgs): Type {
2818
4093
  return internType(new InterfaceType('interface{}'))
2819
4094
  }
2820
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
+
2821
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 {
2822
4145
  if (typeof info === 'string') {
2823
4146
  const registered = builtinGetTypeByName(info)
2824
4147
  if (registered) {
2825
- return internType(typeFromTypeInfo(registered))
4148
+ const typ = typeFromTypeInfoWithSeen(registered, seen)
4149
+ return internType(typ)
2826
4150
  }
2827
- return internType(StructType.createTypeFromFieldInfo(info))
4151
+ return internType(StructType.createTypeFromFieldInfo(info, seen))
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 ?? ''
2828
4185
  }
4186
+ return info.name ?? ''
4187
+ }
4188
+
4189
+ function typeFromStructuredTypeInfoWithSeen(
4190
+ info: $.TypeInfo,
4191
+ seen: Set<string>,
4192
+ ): Type {
2829
4193
  switch (info.kind) {
2830
4194
  case $.TypeKind.Array:
2831
- return internType(
2832
- new ArrayType(
2833
- typeFromTypeInfo(
2834
- info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2835
- ),
2836
- info.length,
4195
+ return new ArrayType(
4196
+ typeFromTypeInfoWithSeen(
4197
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4198
+ seen,
2837
4199
  ),
4200
+ info.length,
2838
4201
  )
2839
4202
  case $.TypeKind.Basic:
2840
- return internType(StructType.createTypeFromFieldInfo(info))
4203
+ return StructType.createTypeFromFieldInfo(info, seen)
2841
4204
  case $.TypeKind.Channel:
2842
- return internType(
2843
- new ChannelType(
2844
- typeFromTypeInfo(
2845
- info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2846
- ),
2847
- chanDirFromTypeInfo(info.direction),
4205
+ return new ChannelType(
4206
+ typeFromTypeInfoWithSeen(
4207
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4208
+ seen,
2848
4209
  ),
4210
+ chanDirFromTypeInfo(info.direction),
2849
4211
  )
2850
4212
  case $.TypeKind.Function:
2851
- return internType(functionTypeFromInfo(info))
4213
+ return functionTypeFromInfo(info, seen)
2852
4214
  case $.TypeKind.Interface:
2853
- return internType(interfaceTypeFromInfo(info))
4215
+ return interfaceTypeFromInfo(info, seen)
2854
4216
  case $.TypeKind.Map:
2855
- return internType(
2856
- new MapType(
2857
- typeFromTypeInfo(
2858
- info.keyType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2859
- ),
2860
- typeFromTypeInfo(
2861
- info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2862
- ),
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,
2863
4225
  ),
2864
4226
  )
2865
4227
  case $.TypeKind.Slice:
2866
- return internType(
2867
- new SliceType(
2868
- typeFromTypeInfo(
2869
- info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2870
- ),
4228
+ return new SliceType(
4229
+ typeFromTypeInfoWithSeen(
4230
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4231
+ seen,
2871
4232
  ),
2872
4233
  )
2873
4234
  case $.TypeKind.Struct:
2874
- return internType(StructType.createTypeFromFieldInfo(info))
4235
+ return StructType.createTypeFromFieldInfo(info, seen)
2875
4236
  case $.TypeKind.Pointer:
2876
- return internType(
2877
- new PointerType(
2878
- typeFromTypeInfo(
2879
- info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2880
- ),
4237
+ return new PointerType(
4238
+ typeFromTypeInfoWithSeen(
4239
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
4240
+ seen,
2881
4241
  ),
2882
4242
  )
2883
4243
  default:
2884
- return internType(StructType.createTypeFromFieldInfo(info))
4244
+ return StructType.createTypeFromFieldInfo(info, seen)
2885
4245
  }
2886
4246
  }
2887
4247
 
2888
- function functionTypeFromInfo(info: $.FunctionTypeInfo): Type {
2889
- if (info.name) {
2890
- 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)
2891
4264
  }
2892
- const params = info.params ?? []
2893
- const paramTypes = params.map((param, index) => {
2894
- const typeName = functionSignatureTypeName(param)
2895
- if (!info.isVariadic || index !== params.length - 1) {
2896
- return typeName
2897
- }
2898
- if (typeName.startsWith('[]')) {
2899
- return '...' + typeName.slice(2)
2900
- }
2901
- 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,
2902
4282
  })
2903
- const resultTypes = (info.results ?? []).map(functionSignatureTypeName)
2904
- let signature = `func(${paramTypes.join(', ')})`
2905
- if (resultTypes.length === 1) {
2906
- 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)))
4293
+ }
4294
+ const info: $.FunctionTypeInfo = {
4295
+ kind: $.TypeKind.Function,
4296
+ params,
4297
+ results,
4298
+ }
4299
+ if (typ.Name() !== '') {
4300
+ info.name = typ.String()
2907
4301
  }
2908
- if (resultTypes.length > 1) {
2909
- signature += ` (${resultTypes.join(', ')})`
4302
+ if (typ.IsVariadic()) {
4303
+ info.isVariadic = true
2910
4304
  }
2911
- return new FunctionType(signature)
4305
+ return info
2912
4306
  }
2913
4307
 
2914
- function functionSignatureTypeName(info: $.TypeInfo | string): string {
2915
- return typeFromTypeInfo(info).String()
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()
4408
+ }
2916
4409
  }
2917
4410
 
2918
- function interfaceTypeFromInfo(info: $.InterfaceTypeInfo): Type {
2919
- if (info.methods.length === 0) {
2920
- return new InterfaceType('interface{}', info.name)
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'
4421
+ }
4422
+
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)
2921
4430
  }
2922
4431
  return new InterfaceType(
2923
- `interface { ${info.methods.map((method) => method.name + '()').join('; ')} }`,
4432
+ interfaceTypeString(methods, seen),
2924
4433
  info.name,
4434
+ methods,
2925
4435
  )
2926
4436
  }
2927
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
+
2928
4565
  function chanDirFromTypeInfo(direction?: 'send' | 'receive' | 'both'): ChanDir {
2929
4566
  switch (direction) {
2930
4567
  case 'send':
@@ -2942,38 +4579,16 @@ function chanDirFromTypeInfo(direction?: 'send' | 'receive' | 'both'): ChanDir {
2942
4579
  */
2943
4580
  export function getInterfaceTypeByName(name: string): Type {
2944
4581
  const typeInfo = builtinGetTypeByName(name)
2945
- if (typeInfo && typeInfo.kind === TypeKind.Interface) {
2946
- return new InterfaceType(name, name)
4582
+ if (typeInfo && isInterfaceTypeInfo(typeInfo)) {
4583
+ return new InterfaceType(name, name, typeInfo.methods ?? [])
2947
4584
  }
2948
4585
  return new InterfaceType('interface{}')
2949
4586
  }
2950
4587
 
2951
4588
  export function getInterfaceLiteralTypeByName(name: string): Type {
2952
4589
  const typeInfo = builtinGetTypeByName(name)
2953
- if (typeInfo && typeInfo.kind === TypeKind.Interface) {
2954
- const methods = (typeInfo as any).methods || []
2955
- if (methods.length === 0) {
2956
- return new InterfaceType('interface{}', name)
2957
- }
2958
- const methodSigs = methods
2959
- .map((m: any) => {
2960
- const args =
2961
- m.args
2962
- ?.map((a: any) => (typeof a === 'string' ? a : 'any'))
2963
- .join(', ') || ''
2964
- const returns = m.returns?.map((r: any) =>
2965
- typeof r === 'string' ? r : 'any',
2966
- )
2967
- let returnSig = ''
2968
- if (returns && returns.length === 1) {
2969
- returnSig = ` ${returns[0]}`
2970
- } else if (returns && returns.length > 1) {
2971
- returnSig = ` (${returns.join(', ')})`
2972
- }
2973
- return `${m.name}(${args})${returnSig}`
2974
- })
2975
- .join('; ')
2976
- return new InterfaceType(`interface { ${methodSigs} }`, name)
4590
+ if (typeInfo && isInterfaceTypeInfo(typeInfo)) {
4591
+ return interfaceTypeFromInfo(typeInfo)
2977
4592
  }
2978
4593
  return new InterfaceType('interface{}')
2979
4594
  }