goscript 0.1.1 → 0.1.3

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 (376) hide show
  1. package/cmd/goscript/cmd-test.go +104 -11
  2. package/cmd/goscript/cmd-test_test.go +1 -1
  3. package/cmd/goscript/cmd_compile.go +9 -0
  4. package/compiler/compile-request.go +31 -0
  5. package/compiler/compiler.go +1 -1
  6. package/compiler/compliance_test.go +0 -2
  7. package/compiler/config.go +2 -0
  8. package/compiler/gotest/package-result.go +2 -0
  9. package/compiler/gotest/request.go +85 -20
  10. package/compiler/gotest/runner.go +733 -96
  11. package/compiler/gotest/runner_test.go +647 -3
  12. package/compiler/lowered-program.go +10 -2
  13. package/compiler/lowering.go +2676 -349
  14. package/compiler/override-facts.go +77 -27
  15. package/compiler/override-registry.go +5 -4
  16. package/compiler/override-registry_test.go +178 -0
  17. package/compiler/package-graph_test.go +62 -7
  18. package/compiler/package-test-graph-variant.go +40 -16
  19. package/compiler/package-test-graph.go +0 -5
  20. package/compiler/package-test-graph_test.go +61 -3
  21. package/compiler/runtime-contract.go +40 -0
  22. package/compiler/semantic-model-types.go +16 -0
  23. package/compiler/semantic-model.go +336 -91
  24. package/compiler/semantic-model_test.go +50 -1
  25. package/compiler/service.go +9 -3
  26. package/compiler/skeleton_test.go +2371 -296
  27. package/compiler/tsworkspace/owner-process-unix_test.go +72 -0
  28. package/compiler/tsworkspace/owner.go +8 -0
  29. package/compiler/tsworkspace/tool-process-other.go +14 -0
  30. package/compiler/tsworkspace/tool-process-unix.go +19 -0
  31. package/compiler/typescript-emitter.go +149 -10
  32. package/dist/gs/builtin/builtin.d.ts +20 -1
  33. package/dist/gs/builtin/builtin.js +246 -26
  34. package/dist/gs/builtin/builtin.js.map +1 -1
  35. package/dist/gs/builtin/channel.d.ts +24 -10
  36. package/dist/gs/builtin/channel.js +143 -34
  37. package/dist/gs/builtin/channel.js.map +1 -1
  38. package/dist/gs/builtin/defer.d.ts +1 -0
  39. package/dist/gs/builtin/defer.js +12 -2
  40. package/dist/gs/builtin/defer.js.map +1 -1
  41. package/dist/gs/builtin/hostio.d.ts +9 -0
  42. package/dist/gs/builtin/hostio.js +25 -0
  43. package/dist/gs/builtin/hostio.js.map +1 -1
  44. package/dist/gs/builtin/map.js +40 -6
  45. package/dist/gs/builtin/map.js.map +1 -1
  46. package/dist/gs/builtin/print.js.map +1 -1
  47. package/dist/gs/builtin/slice.d.ts +43 -9
  48. package/dist/gs/builtin/slice.js +437 -234
  49. package/dist/gs/builtin/slice.js.map +1 -1
  50. package/dist/gs/builtin/type.d.ts +2 -0
  51. package/dist/gs/builtin/type.js +55 -10
  52. package/dist/gs/builtin/type.js.map +1 -1
  53. package/dist/gs/builtin/varRef.d.ts +2 -0
  54. package/dist/gs/builtin/varRef.js.map +1 -1
  55. package/dist/gs/bytes/buffer.gs.js +28 -28
  56. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  57. package/dist/gs/bytes/bytes.gs.d.ts +7 -5
  58. package/dist/gs/bytes/bytes.gs.js +10 -4
  59. package/dist/gs/bytes/bytes.gs.js.map +1 -1
  60. package/dist/gs/bytes/iter.gs.js +13 -13
  61. package/dist/gs/bytes/iter.gs.js.map +1 -1
  62. package/dist/gs/compress/zlib/index.d.ts +26 -0
  63. package/dist/gs/compress/zlib/index.js +168 -0
  64. package/dist/gs/compress/zlib/index.js.map +1 -0
  65. package/dist/gs/context/context.d.ts +1 -1
  66. package/dist/gs/context/context.js +8 -3
  67. package/dist/gs/context/context.js.map +1 -1
  68. package/dist/gs/crypto/ecdh/index.d.ts +52 -0
  69. package/dist/gs/crypto/ecdh/index.js +226 -0
  70. package/dist/gs/crypto/ecdh/index.js.map +1 -0
  71. package/dist/gs/crypto/ed25519/index.d.ts +34 -0
  72. package/dist/gs/crypto/ed25519/index.js +160 -0
  73. package/dist/gs/crypto/ed25519/index.js.map +1 -0
  74. package/dist/gs/crypto/internal/constanttime/index.d.ts +4 -0
  75. package/dist/gs/crypto/internal/constanttime/index.js +18 -0
  76. package/dist/gs/crypto/internal/constanttime/index.js.map +1 -0
  77. package/dist/gs/crypto/rand/index.d.ts +2 -0
  78. package/dist/gs/crypto/rand/index.js +85 -0
  79. package/dist/gs/crypto/rand/index.js.map +1 -1
  80. package/dist/gs/crypto/sha1/index.d.ts +5 -0
  81. package/dist/gs/crypto/sha1/index.js +106 -0
  82. package/dist/gs/crypto/sha1/index.js.map +1 -0
  83. package/dist/gs/crypto/sha256/index.d.ts +8 -0
  84. package/dist/gs/crypto/sha256/index.js +118 -0
  85. package/dist/gs/crypto/sha256/index.js.map +1 -0
  86. package/dist/gs/crypto/sha512/index.d.ts +14 -0
  87. package/dist/gs/crypto/sha512/index.js +129 -0
  88. package/dist/gs/crypto/sha512/index.js.map +1 -0
  89. package/dist/gs/encoding/json/index.d.ts +3 -0
  90. package/dist/gs/encoding/json/index.js +15 -0
  91. package/dist/gs/encoding/json/index.js.map +1 -1
  92. package/dist/gs/errors/errors.js +29 -6
  93. package/dist/gs/errors/errors.js.map +1 -1
  94. package/dist/gs/fmt/fmt.d.ts +1 -1
  95. package/dist/gs/fmt/fmt.js +64 -3
  96. package/dist/gs/fmt/fmt.js.map +1 -1
  97. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +7 -7
  98. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +52 -18
  99. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  100. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +56 -20
  101. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -1
  102. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +57 -3
  103. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +366 -1
  104. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
  105. package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +20 -0
  106. package/dist/gs/github.com/aperturerobotics/util/conc/index.js +134 -0
  107. package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +1 -0
  108. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
  109. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.d.ts +3 -0
  110. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js +50 -0
  111. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js.map +1 -0
  112. package/dist/gs/github.com/klauspost/compress/internal/le/index.js +3 -2
  113. package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -1
  114. package/dist/gs/github.com/mr-tron/base58/base58/index.d.ts +27 -0
  115. package/dist/gs/github.com/mr-tron/base58/base58/index.js +172 -0
  116. package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -0
  117. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.d.ts +21 -0
  118. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js +22 -0
  119. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js.map +1 -0
  120. package/dist/gs/go/token/index.js +11 -4
  121. package/dist/gs/go/token/index.js.map +1 -1
  122. package/dist/gs/hash/fnv/index.d.ts +57 -0
  123. package/dist/gs/hash/fnv/index.js +299 -0
  124. package/dist/gs/hash/fnv/index.js.map +1 -0
  125. package/dist/gs/hash/index.d.ts +17 -0
  126. package/dist/gs/hash/index.js +94 -0
  127. package/dist/gs/hash/index.js.map +1 -0
  128. package/dist/gs/io/fs/readlink.js +2 -6
  129. package/dist/gs/io/fs/readlink.js.map +1 -1
  130. package/dist/gs/io/fs/walk.js.map +1 -1
  131. package/dist/gs/io/io.d.ts +8 -5
  132. package/dist/gs/io/io.js +20 -2
  133. package/dist/gs/io/io.js.map +1 -1
  134. package/dist/gs/iter/iter.d.ts +3 -2
  135. package/dist/gs/iter/iter.js.map +1 -1
  136. package/dist/gs/maps/iter.d.ts +5 -5
  137. package/dist/gs/maps/iter.js +48 -21
  138. package/dist/gs/maps/iter.js.map +1 -1
  139. package/dist/gs/maps/maps.d.ts +6 -6
  140. package/dist/gs/math/bits/index.js +14 -24
  141. package/dist/gs/math/bits/index.js.map +1 -1
  142. package/dist/gs/mime/index.js +3 -1
  143. package/dist/gs/mime/index.js.map +1 -1
  144. package/dist/gs/net/http/httptest/index.d.ts +20 -1
  145. package/dist/gs/net/http/httptest/index.js +85 -3
  146. package/dist/gs/net/http/httptest/index.js.map +1 -1
  147. package/dist/gs/net/http/index.d.ts +118 -6
  148. package/dist/gs/net/http/index.js +389 -14
  149. package/dist/gs/net/http/index.js.map +1 -1
  150. package/dist/gs/net/http/pprof/index.d.ts +8 -0
  151. package/dist/gs/net/http/pprof/index.js +59 -0
  152. package/dist/gs/net/http/pprof/index.js.map +1 -0
  153. package/dist/gs/os/error.gs.js +9 -7
  154. package/dist/gs/os/error.gs.js.map +1 -1
  155. package/dist/gs/os/types_js.gs.js +95 -15
  156. package/dist/gs/os/types_js.gs.js.map +1 -1
  157. package/dist/gs/os/zero_copy_posix.gs.js +1 -1
  158. package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
  159. package/dist/gs/path/filepath/match.js.map +1 -1
  160. package/dist/gs/path/filepath/path.d.ts +5 -3
  161. package/dist/gs/path/filepath/path.js +65 -10
  162. package/dist/gs/path/filepath/path.js.map +1 -1
  163. package/dist/gs/reflect/index.d.ts +3 -2
  164. package/dist/gs/reflect/index.js +2 -1
  165. package/dist/gs/reflect/index.js.map +1 -1
  166. package/dist/gs/reflect/iter.js +2 -2
  167. package/dist/gs/reflect/iter.js.map +1 -1
  168. package/dist/gs/reflect/map.js +26 -0
  169. package/dist/gs/reflect/map.js.map +1 -1
  170. package/dist/gs/reflect/type.d.ts +24 -5
  171. package/dist/gs/reflect/type.js +390 -38
  172. package/dist/gs/reflect/type.js.map +1 -1
  173. package/dist/gs/reflect/types.d.ts +1 -0
  174. package/dist/gs/reflect/types.js +3 -1
  175. package/dist/gs/reflect/types.js.map +1 -1
  176. package/dist/gs/reflect/value.d.ts +4 -1
  177. package/dist/gs/reflect/value.js +39 -1
  178. package/dist/gs/reflect/value.js.map +1 -1
  179. package/dist/gs/reflect/visiblefields.js +1 -1
  180. package/dist/gs/reflect/visiblefields.js.map +1 -1
  181. package/dist/gs/runtime/debug/index.d.ts +39 -0
  182. package/dist/gs/runtime/debug/index.js +58 -0
  183. package/dist/gs/runtime/debug/index.js.map +1 -1
  184. package/dist/gs/runtime/pprof/index.d.ts +20 -0
  185. package/dist/gs/runtime/pprof/index.js +85 -0
  186. package/dist/gs/runtime/pprof/index.js.map +1 -0
  187. package/dist/gs/runtime/trace/index.d.ts +19 -0
  188. package/dist/gs/runtime/trace/index.js +64 -0
  189. package/dist/gs/runtime/trace/index.js.map +1 -0
  190. package/dist/gs/slices/slices.d.ts +24 -9
  191. package/dist/gs/slices/slices.js +229 -24
  192. package/dist/gs/slices/slices.js.map +1 -1
  193. package/dist/gs/sort/slice.gs.d.ts +5 -3
  194. package/dist/gs/sort/slice.gs.js +55 -17
  195. package/dist/gs/sort/slice.gs.js.map +1 -1
  196. package/dist/gs/strings/builder.js +26 -17
  197. package/dist/gs/strings/builder.js.map +1 -1
  198. package/dist/gs/strings/iter.js +140 -75
  199. package/dist/gs/strings/iter.js.map +1 -1
  200. package/dist/gs/strings/replace.js +2 -2
  201. package/dist/gs/strings/replace.js.map +1 -1
  202. package/dist/gs/strings/strings.js +52 -6
  203. package/dist/gs/strings/strings.js.map +1 -1
  204. package/dist/gs/sync/sync.d.ts +6 -3
  205. package/dist/gs/sync/sync.js +39 -11
  206. package/dist/gs/sync/sync.js.map +1 -1
  207. package/dist/gs/syscall/errors.d.ts +116 -112
  208. package/dist/gs/syscall/errors.js +38 -1
  209. package/dist/gs/syscall/errors.js.map +1 -1
  210. package/dist/gs/syscall/fs.d.ts +2 -8
  211. package/dist/gs/syscall/fs.js.map +1 -1
  212. package/dist/gs/syscall/js/index.js +20 -12
  213. package/dist/gs/syscall/js/index.js.map +1 -1
  214. package/dist/gs/syscall/types.d.ts +4 -1
  215. package/dist/gs/syscall/types.js.map +1 -1
  216. package/dist/gs/testing/testing.d.ts +4 -3
  217. package/dist/gs/testing/testing.js +21 -4
  218. package/dist/gs/testing/testing.js.map +1 -1
  219. package/dist/gs/time/time.js +22 -0
  220. package/dist/gs/time/time.js.map +1 -1
  221. package/dist/gs/unicode/unicode.js.map +1 -1
  222. package/dist/gs/unique/index.js +7 -2
  223. package/dist/gs/unique/index.js.map +1 -1
  224. package/go.mod +8 -8
  225. package/go.sum +14 -23
  226. package/gs/builtin/builtin.ts +364 -37
  227. package/gs/builtin/channel.ts +208 -38
  228. package/gs/builtin/defer.ts +13 -2
  229. package/gs/builtin/hostio.test.ts +1 -0
  230. package/gs/builtin/hostio.ts +38 -0
  231. package/gs/builtin/map.ts +46 -6
  232. package/gs/builtin/print.ts +12 -3
  233. package/gs/builtin/runtime-contract.test.ts +290 -10
  234. package/gs/builtin/slice.test.ts +70 -0
  235. package/gs/builtin/slice.ts +566 -255
  236. package/gs/builtin/type.ts +63 -10
  237. package/gs/builtin/varRef.ts +2 -0
  238. package/gs/bytes/buffer.gs.ts +28 -28
  239. package/gs/bytes/bytes.gs.ts +19 -10
  240. package/gs/bytes/bytes.test.ts +17 -0
  241. package/gs/bytes/iter.gs.ts +13 -14
  242. package/gs/compress/zlib/index.test.ts +28 -0
  243. package/gs/compress/zlib/index.ts +200 -0
  244. package/gs/compress/zlib/meta.json +3 -0
  245. package/gs/context/context.test.ts +36 -2
  246. package/gs/context/context.ts +9 -4
  247. package/gs/crypto/ecdh/index.test.ts +43 -0
  248. package/gs/crypto/ecdh/index.ts +274 -0
  249. package/gs/crypto/ed25519/index.test.ts +41 -0
  250. package/gs/crypto/ed25519/index.ts +238 -0
  251. package/gs/crypto/ed25519/meta.json +13 -0
  252. package/gs/crypto/internal/constanttime/index.test.ts +25 -0
  253. package/gs/crypto/internal/constanttime/index.ts +22 -0
  254. package/gs/crypto/rand/index.test.ts +89 -1
  255. package/gs/crypto/rand/index.ts +103 -1
  256. package/gs/crypto/rand/meta.json +4 -1
  257. package/gs/crypto/sha1/index.test.ts +28 -0
  258. package/gs/crypto/sha1/index.ts +130 -0
  259. package/gs/crypto/sha1/meta.json +8 -0
  260. package/gs/crypto/sha256/index.test.ts +78 -0
  261. package/gs/crypto/sha256/index.ts +150 -0
  262. package/gs/crypto/sha256/meta.json +9 -0
  263. package/gs/crypto/sha512/index.test.ts +31 -0
  264. package/gs/crypto/sha512/index.ts +161 -0
  265. package/gs/crypto/sha512/meta.json +11 -0
  266. package/gs/encoding/json/index.test.ts +25 -3
  267. package/gs/encoding/json/index.ts +21 -3
  268. package/gs/errors/errors.test.ts +4 -1
  269. package/gs/errors/errors.ts +32 -8
  270. package/gs/fmt/fmt.test.ts +23 -1
  271. package/gs/fmt/fmt.ts +76 -10
  272. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +62 -7
  273. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +78 -36
  274. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +32 -11
  275. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +122 -43
  276. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +31 -0
  277. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +518 -4
  278. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +6 -0
  279. package/gs/github.com/aperturerobotics/util/conc/index.test.ts +30 -0
  280. package/gs/github.com/aperturerobotics/util/conc/index.ts +172 -0
  281. package/gs/github.com/aperturerobotics/util/conc/meta.json +9 -0
  282. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.ts +1 -4
  283. package/gs/github.com/hack-pad/safejs/internal/catch/index.test.ts +35 -0
  284. package/gs/github.com/hack-pad/safejs/internal/catch/index.ts +65 -0
  285. package/gs/github.com/hack-pad/safejs/internal/catch/meta.json +9 -0
  286. package/gs/github.com/klauspost/compress/internal/le/index.test.ts +2 -1
  287. package/gs/github.com/klauspost/compress/internal/le/index.ts +6 -5
  288. package/gs/github.com/mr-tron/base58/base58/index.test.ts +70 -0
  289. package/gs/github.com/mr-tron/base58/base58/index.ts +231 -0
  290. package/gs/github.com/mr-tron/base58/base58/meta.json +3 -0
  291. package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +46 -0
  292. package/gs/github.com/zeebo/blake3/internal/consts/index.ts +26 -0
  293. package/gs/go/token/index.ts +17 -4
  294. package/gs/hash/fnv/index.test.ts +67 -0
  295. package/gs/hash/fnv/index.ts +351 -0
  296. package/gs/hash/fnv/meta.json +3 -0
  297. package/gs/hash/index.test.ts +37 -0
  298. package/gs/hash/index.ts +118 -0
  299. package/gs/hash/meta.json +5 -0
  300. package/gs/internal/byteorder/index.test.ts +6 -6
  301. package/gs/io/fs/readlink.ts +40 -48
  302. package/gs/io/fs/walk.ts +10 -2
  303. package/gs/io/io.test.ts +64 -0
  304. package/gs/io/io.ts +34 -13
  305. package/gs/iter/iter.ts +8 -2
  306. package/gs/maps/iter.ts +69 -26
  307. package/gs/maps/maps.test.ts +23 -0
  308. package/gs/maps/maps.ts +6 -6
  309. package/gs/math/bits/index.test.ts +20 -0
  310. package/gs/math/bits/index.ts +15 -28
  311. package/gs/mime/index.ts +8 -2
  312. package/gs/net/http/httptest/index.test.ts +85 -0
  313. package/gs/net/http/httptest/index.ts +113 -3
  314. package/gs/net/http/index.test.ts +159 -1
  315. package/gs/net/http/index.ts +515 -15
  316. package/gs/net/http/meta.json +6 -0
  317. package/gs/net/http/pprof/index.test.ts +47 -0
  318. package/gs/net/http/pprof/index.ts +65 -0
  319. package/gs/os/error.gs.ts +9 -10
  320. package/gs/os/error.test.ts +41 -0
  321. package/gs/os/file_unix_js.test.ts +55 -0
  322. package/gs/os/tempfile.gs.test.ts +37 -10
  323. package/gs/os/types_js.gs.ts +94 -15
  324. package/gs/os/zero_copy_posix.gs.ts +1 -2
  325. package/gs/path/filepath/match.ts +4 -1
  326. package/gs/path/filepath/meta.json +6 -0
  327. package/gs/path/filepath/path.test.ts +57 -2
  328. package/gs/path/filepath/path.ts +91 -12
  329. package/gs/reflect/field.test.ts +63 -0
  330. package/gs/reflect/index.ts +4 -1
  331. package/gs/reflect/iter.ts +2 -2
  332. package/gs/reflect/map.test.ts +24 -2
  333. package/gs/reflect/map.ts +35 -0
  334. package/gs/reflect/type.ts +543 -60
  335. package/gs/reflect/typefor.test.ts +100 -0
  336. package/gs/reflect/types.ts +3 -1
  337. package/gs/reflect/value.ts +50 -1
  338. package/gs/reflect/visiblefields.ts +1 -1
  339. package/gs/runtime/debug/index.test.ts +22 -1
  340. package/gs/runtime/debug/index.ts +88 -0
  341. package/gs/runtime/pprof/index.test.ts +36 -0
  342. package/gs/runtime/pprof/index.ts +104 -0
  343. package/gs/runtime/pprof/meta.json +6 -0
  344. package/gs/runtime/trace/index.test.ts +45 -0
  345. package/gs/runtime/trace/index.ts +97 -0
  346. package/gs/runtime/trace/meta.json +7 -0
  347. package/gs/slices/meta.json +2 -1
  348. package/gs/slices/slices.test.ts +86 -0
  349. package/gs/slices/slices.ts +284 -37
  350. package/gs/sort/slice.gs.ts +73 -23
  351. package/gs/sort/slice.test.ts +40 -0
  352. package/gs/strings/builder.test.ts +8 -0
  353. package/gs/strings/builder.ts +29 -17
  354. package/gs/strings/iter.test.ts +5 -7
  355. package/gs/strings/iter.ts +146 -71
  356. package/gs/strings/replace.test.ts +1 -4
  357. package/gs/strings/replace.ts +6 -6
  358. package/gs/strings/strings.test.ts +4 -0
  359. package/gs/strings/strings.ts +54 -6
  360. package/gs/sync/meta.json +1 -0
  361. package/gs/sync/sync.test.ts +57 -1
  362. package/gs/sync/sync.ts +45 -13
  363. package/gs/syscall/errors.ts +158 -115
  364. package/gs/syscall/fs.ts +8 -8
  365. package/gs/syscall/js/index.ts +49 -22
  366. package/gs/syscall/net.test.ts +26 -0
  367. package/gs/syscall/types.ts +7 -2
  368. package/gs/testing/testing.test.ts +56 -0
  369. package/gs/testing/testing.ts +27 -10
  370. package/gs/time/meta.json +2 -2
  371. package/gs/time/time.test.ts +4 -0
  372. package/gs/time/time.ts +33 -2
  373. package/gs/unicode/unicode.test.ts +14 -3
  374. package/gs/unicode/unicode.ts +1 -5
  375. package/gs/unique/index.ts +9 -2
  376. package/package.json +3 -3
@@ -15,6 +15,7 @@ import (
15
15
  "slices"
16
16
  "strconv"
17
17
  "strings"
18
+ "unicode/utf8"
18
19
  )
19
20
 
20
21
  // LoweringOwner owns conversion from the semantic model to compiler IR.
@@ -86,10 +87,13 @@ func (o *LoweringOwner) lowerPackage(model *SemanticModel, semPkg *semanticPacka
86
87
  pkgPath: semPkg.pkgPath,
87
88
  name: semPkg.name,
88
89
  }
90
+ declFiles := packageDeclFiles(semPkg)
91
+ outputNames := packageOutputNames(semPkg)
92
+ lazyPackageVars := o.lazyPackageVars(semPkg, declFiles)
89
93
  var diagnostics []Diagnostic
90
94
  for idx, file := range semPkg.source.Syntax {
91
95
  sourcePath := sourceFilePath(semPkg, idx, file)
92
- loweredFile, fileDiagnostics := o.lowerFile(model, semPkg, file, sourcePath)
96
+ loweredFile, fileDiagnostics := o.lowerFile(model, semPkg, file, sourcePath, declFiles, outputNames, lazyPackageVars)
93
97
  diagnostics = append(diagnostics, fileDiagnostics...)
94
98
  if loweredFile != nil {
95
99
  loweredPkg.files = append(loweredPkg.files, loweredFile)
@@ -118,6 +122,9 @@ func (o *LoweringOwner) lowerFile(
118
122
  semPkg *semanticPackage,
119
123
  file *ast.File,
120
124
  sourcePath string,
125
+ declFiles map[types.Object]string,
126
+ outputNames map[string]string,
127
+ lazyPackageVars map[types.Object]bool,
121
128
  ) (*loweredFile, []Diagnostic) {
122
129
  associatedMethods := o.methodDeclsForFileTypes(semPkg, file)
123
130
  relevantImportFiles := map[string]bool{sourcePath: true}
@@ -138,7 +145,9 @@ func (o *LoweringOwner) lowerFile(
138
145
  importAliases := make(map[string]string)
139
146
  importPaths := make(map[string]string)
140
147
  importNames := make(map[string]string)
141
- reservedImportAliases := localDeclarationNames(semPkg, file, associatedMethods)
148
+ importObjects := make(map[*types.PkgName]string)
149
+ localRefs := o.analyzeLocalFileReferences(semPkg, file, sourcePath, associatedMethods, declFiles, outputNames)
150
+ reservedImportAliases := localRefs.reservedNames
142
151
  seenImport := make(map[string]bool)
143
152
  for idx, importFile := range semPkg.source.Syntax {
144
153
  importSourcePath := sourceFilePath(semPkg, idx, importFile)
@@ -170,36 +179,51 @@ func (o *LoweringOwner) lowerFile(
170
179
  importAliases[alias] = pkgName.Imported().Path()
171
180
  importPaths[pkgName.Imported().Path()] = alias
172
181
  importNames[name] = alias
182
+ importObjects[pkgName] = alias
173
183
  loweredFile.imports = append(loweredFile.imports, loweredImport{
174
- alias: alias,
175
- source: source,
184
+ alias: alias,
185
+ source: source,
186
+ sideEffect: true,
176
187
  })
177
188
  }
178
189
  }
179
- for importSourcePath := range relevantImportFiles {
180
- o.addGeneratedTypeImports(model, semPkg, importSourcePath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport)
181
- }
182
- localAliases, localAliasSources, implicitImports := o.localFileAliases(semPkg, file, sourcePath, associatedMethods)
183
- lazyPackageVars := o.lazyPackageVars(semPkg)
184
- implicitImportPaths := make([]string, 0, len(implicitImports))
185
- for pkgPath := range implicitImports {
190
+ implicitImportPaths := make([]string, 0, len(localRefs.implicitImports))
191
+ for pkgPath := range localRefs.implicitImports {
186
192
  if pkgPath != "" && pkgPath != semPkg.pkgPath {
187
193
  implicitImportPaths = append(implicitImportPaths, pkgPath)
188
194
  }
189
195
  }
190
196
  slices.Sort(implicitImportPaths)
191
197
  for _, pkgPath := range implicitImportPaths {
192
- o.addGeneratedImportPath(model, pkgPath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport)
198
+ o.addGeneratedImportPath(
199
+ model,
200
+ pkgPath,
201
+ loweredFile,
202
+ importAliases,
203
+ importPaths,
204
+ reservedImportAliases,
205
+ seenImport,
206
+ !localRefs.implicitRuntime[pkgPath],
207
+ )
208
+ }
209
+ for importSourcePath := range relevantImportFiles {
210
+ o.addGeneratedTypeImports(model, semPkg, importSourcePath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport)
193
211
  }
194
- localImports := make([]loweredImport, 0, len(localAliases))
212
+ localImports := make([]loweredImport, 0, len(localRefs.aliases))
195
213
  seenLocalImport := make(map[string]bool)
196
- for _, alias := range localAliases {
214
+ for _, alias := range localRefs.aliases {
197
215
  if seenLocalImport[alias] {
198
216
  continue
199
217
  }
200
218
  seenLocalImport[alias] = true
201
- source := localAliasSources[alias]
202
- localImports = append(localImports, loweredImport{alias: alias, source: source})
219
+ source := localRefs.aliasSources[alias]
220
+ typeOnly := !localRefs.runtimeAliases[alias]
221
+ localImports = append(localImports, loweredImport{
222
+ alias: alias,
223
+ source: source,
224
+ sideEffect: !typeOnly,
225
+ typeOnly: typeOnly,
226
+ })
203
227
  }
204
228
  slices.SortFunc(localImports, func(a, b loweredImport) int {
205
229
  return cmp.Compare(a.alias, b.alias)
@@ -213,15 +237,21 @@ func (o *LoweringOwner) lowerFile(
213
237
  importAliases: importAliases,
214
238
  importPaths: importPaths,
215
239
  importNames: importNames,
240
+ importObjects: importObjects,
216
241
  sourcePath: sourcePath,
217
- localAliases: localAliases,
242
+ localAliases: localRefs.aliases,
218
243
  lazyPackageVars: lazyPackageVars,
219
244
  tempNames: newTempNameOwner(),
220
245
  topLevel: true,
221
246
  }
222
247
  var diagnostics []Diagnostic
248
+ var packageInitCalls []string
223
249
  appendDecls := func(decls []loweredDecl) {
224
250
  for _, decl := range decls {
251
+ if decl.packageInitCall != "" {
252
+ packageInitCalls = append(packageInitCalls, decl.packageInitCall)
253
+ continue
254
+ }
225
255
  loweredFile.decls = append(loweredFile.decls, decl)
226
256
  if decl.indexExport != "" {
227
257
  loweredFile.exports = append(loweredFile.exports, decl.indexExport)
@@ -229,6 +259,9 @@ func (o *LoweringOwner) lowerFile(
229
259
  if decl.typeIndexExport != "" {
230
260
  loweredFile.typeExports = append(loweredFile.typeExports, decl.typeIndexExport)
231
261
  }
262
+ if decl.sideEffect {
263
+ loweredFile.sideEffect = true
264
+ }
232
265
  if decl.function != nil && decl.function.indexExported && decl.function.name != "main" {
233
266
  loweredFile.exports = append(loweredFile.exports, decl.function.name)
234
267
  }
@@ -252,6 +285,9 @@ func (o *LoweringOwner) lowerFile(
252
285
  lowerDecl(decl)
253
286
  }
254
287
  }
288
+ for _, call := range packageInitCalls {
289
+ loweredFile.decls = append(loweredFile.decls, loweredDecl{code: "await " + call})
290
+ }
255
291
  for _, decl := range loweredFile.decls {
256
292
  if decl.function == nil || !decl.function.init {
257
293
  continue
@@ -287,7 +323,7 @@ func (o *LoweringOwner) addGeneratedTypeImports(
287
323
  }
288
324
  slices.Sort(pkgPaths)
289
325
  for _, pkgPath := range pkgPaths {
290
- o.addGeneratedImportPath(model, pkgPath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport)
326
+ o.addGeneratedImportPath(model, pkgPath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport, true)
291
327
  }
292
328
  }
293
329
 
@@ -299,6 +335,7 @@ func (o *LoweringOwner) addGeneratedImportPath(
299
335
  importPaths map[string]string,
300
336
  reservedImportAliases map[string]bool,
301
337
  seenImport map[string]bool,
338
+ typeOnly bool,
302
339
  ) {
303
340
  if !o.hasGeneratedImportPackage(model, pkgPath) {
304
341
  return
@@ -317,8 +354,10 @@ func (o *LoweringOwner) addGeneratedImportPath(
317
354
  importAliases[alias] = pkgPath
318
355
  importPaths[pkgPath] = alias
319
356
  loweredFile.imports = append(loweredFile.imports, loweredImport{
320
- alias: alias,
321
- source: source,
357
+ alias: alias,
358
+ source: source,
359
+ sideEffect: !typeOnly,
360
+ typeOnly: typeOnly,
322
361
  })
323
362
  }
324
363
 
@@ -351,36 +390,6 @@ func uniqueImportAlias(alias string, pkgPath string, importAliases map[string]st
351
390
  }
352
391
  }
353
392
 
354
- func localDeclarationNames(semPkg *semanticPackage, file *ast.File, associatedMethods []*ast.FuncDecl) map[string]bool {
355
- if semPkg == nil || semPkg.source == nil {
356
- return nil
357
- }
358
- names := make(map[string]bool)
359
- inspect := func(node ast.Node) bool {
360
- ident, ok := node.(*ast.Ident)
361
- if !ok {
362
- return true
363
- }
364
- obj := semPkg.source.TypesInfo.Defs[ident]
365
- if obj == nil {
366
- return true
367
- }
368
- if _, ok := obj.(*types.PkgName); ok {
369
- return true
370
- }
371
- name := safeIdentifier(obj.Name())
372
- if name != "_" {
373
- names[name] = true
374
- }
375
- return true
376
- }
377
- ast.Inspect(file, inspect)
378
- for _, methodDecl := range associatedMethods {
379
- ast.Inspect(methodDecl, inspect)
380
- }
381
- return names
382
- }
383
-
384
393
  func (o *LoweringOwner) methodDeclsForFileTypes(semPkg *semanticPackage, file *ast.File) []*ast.FuncDecl {
385
394
  if semPkg == nil || semPkg.source == nil || file == nil {
386
395
  return nil
@@ -433,54 +442,89 @@ func (o *LoweringOwner) methodDeclsForFileTypes(semPkg *semanticPackage, file *a
433
442
  return methods
434
443
  }
435
444
 
436
- func (o *LoweringOwner) localFileAliases(
445
+ type localFileReferenceAnalysis struct {
446
+ reservedNames map[string]bool
447
+ aliases map[types.Object]string
448
+ aliasSources map[string]string
449
+ runtimeAliases map[string]bool
450
+ implicitImports map[string]bool
451
+ implicitRuntime map[string]bool
452
+ }
453
+
454
+ func (o *LoweringOwner) analyzeLocalFileReferences(
437
455
  semPkg *semanticPackage,
438
456
  file *ast.File,
439
457
  sourcePath string,
440
458
  associatedMethods []*ast.FuncDecl,
441
- ) (map[types.Object]string, map[string]string, map[string]bool) {
442
- declFiles := make(map[types.Object]string)
443
- for _, decl := range semPkg.declarations {
444
- if decl.object == nil || decl.position.file == "" {
445
- continue
446
- }
447
- declFiles[decl.object] = decl.position.file
448
- }
449
- outputNames := make(map[string]string)
450
- for idx, syntax := range semPkg.source.Syntax {
451
- outputSourcePath := sourceFilePath(semPkg, idx, syntax)
452
- outputNames[outputSourcePath] = sourceOutputName(outputSourcePath)
459
+ declFiles map[types.Object]string,
460
+ outputNames map[string]string,
461
+ ) localFileReferenceAnalysis {
462
+ analysis := localFileReferenceAnalysis{
463
+ reservedNames: make(map[string]bool),
464
+ aliases: make(map[types.Object]string),
465
+ aliasSources: make(map[string]string),
466
+ runtimeAliases: make(map[string]bool),
467
+ implicitImports: make(map[string]bool),
468
+ implicitRuntime: make(map[string]bool),
453
469
  }
454
- aliases := make(map[types.Object]string)
455
- aliasSources := make(map[string]string)
456
- implicitImports := make(map[string]bool)
457
470
  seenObjects := make(map[types.Object]bool)
458
471
  seenTypes := make(map[types.Type]bool)
459
472
  var addTypeDeps func(typ types.Type)
460
- var addObject func(obj types.Object)
461
- addObject = func(obj types.Object) {
462
- if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != semPkg.pkgPath {
473
+ var addRuntimeTypeDeps func(typ types.Type)
474
+ var addRuntimeTypeOwnerDeps func(typ types.Type)
475
+ var addObject func(obj types.Object, runtime bool)
476
+ addObject = func(obj types.Object, runtime bool) {
477
+ if obj == nil || obj.Pkg() == nil {
463
478
  return
464
479
  }
465
- if seenObjects[obj] {
480
+ if obj.Pkg().Path() != semPkg.pkgPath {
481
+ if runtime {
482
+ analysis.implicitImports[obj.Pkg().Path()] = true
483
+ analysis.implicitRuntime[obj.Pkg().Path()] = true
484
+ }
466
485
  return
467
486
  }
468
- seenObjects[obj] = true
469
487
  declFile := declFiles[obj]
488
+ if declFile == "" {
489
+ if fn, ok := obj.(*types.Func); ok {
490
+ if decl := functionDeclForObject(semPkg, fn); decl != nil {
491
+ declFile = sourcePos(semPkg.source, decl.Pos()).file
492
+ }
493
+ }
494
+ }
470
495
  if declFile != "" && declFile != sourcePath {
471
496
  outputName := outputNames[declFile]
472
497
  if outputName != "" {
473
498
  alias := "__goscript_" + safeIdentifier(strings.TrimSuffix(outputName, ".gs.ts"))
474
- aliases[obj] = alias
475
- aliasSources[alias] = "./" + outputName
499
+ analysis.aliases[obj] = alias
500
+ analysis.aliasSources[alias] = "./" + outputName
501
+ if runtime {
502
+ analysis.runtimeAliases[alias] = true
503
+ }
476
504
  }
477
505
  }
506
+ if runtime {
507
+ if alias := analysis.aliases[obj]; alias != "" {
508
+ analysis.runtimeAliases[alias] = true
509
+ }
510
+ }
511
+ if seenObjects[obj] {
512
+ return
513
+ }
514
+ seenObjects[obj] = true
478
515
  switch typed := obj.(type) {
479
516
  case *types.TypeName:
480
517
  addTypeDeps(typed.Type())
518
+ if named, ok := types.Unalias(typed.Type()).(*types.Named); ok {
519
+ if structType := structUnderlyingType(named); structType != nil {
520
+ for field := range structType.Fields() {
521
+ addRuntimeTypeDeps(field.Type())
522
+ }
523
+ }
524
+ }
481
525
  if named, ok := types.Unalias(typed.Type()).(*types.Named); ok {
482
526
  for method := range named.Methods() {
483
- addObject(method)
527
+ addObject(method, false)
484
528
  }
485
529
  }
486
530
  case *types.Var:
@@ -514,7 +558,7 @@ func (o *LoweringOwner) localFileAliases(
514
558
  seenTypes[typ] = true
515
559
  if alias, ok := typ.(*types.Alias); ok {
516
560
  if obj := alias.Obj(); obj != nil && obj.Pkg() != nil && obj.Pkg().Path() != semPkg.pkgPath {
517
- implicitImports[obj.Pkg().Path()] = true
561
+ analysis.implicitImports[obj.Pkg().Path()] = true
518
562
  if args := alias.TypeArgs(); args != nil {
519
563
  for t := range args.Types() {
520
564
  addTypeDeps(t)
@@ -523,7 +567,7 @@ func (o *LoweringOwner) localFileAliases(
523
567
  addTypeDeps(alias.Rhs())
524
568
  return
525
569
  }
526
- addObject(alias.Obj())
570
+ addObject(alias.Obj(), false)
527
571
  if args := alias.TypeArgs(); args != nil {
528
572
  for t := range args.Types() {
529
573
  addTypeDeps(t)
@@ -534,7 +578,7 @@ func (o *LoweringOwner) localFileAliases(
534
578
  }
535
579
  if named, ok := types.Unalias(typ).(*types.Named); ok {
536
580
  if obj := named.Obj(); obj != nil && obj.Pkg() != nil && obj.Pkg().Path() != semPkg.pkgPath {
537
- implicitImports[obj.Pkg().Path()] = true
581
+ analysis.implicitImports[obj.Pkg().Path()] = true
538
582
  if args := named.TypeArgs(); args != nil {
539
583
  for t := range args.Types() {
540
584
  addTypeDeps(t)
@@ -542,7 +586,7 @@ func (o *LoweringOwner) localFileAliases(
542
586
  }
543
587
  return
544
588
  }
545
- addObject(named.Obj())
589
+ addObject(named.Obj(), false)
546
590
  if args := named.TypeArgs(); args != nil {
547
591
  for t := range args.Types() {
548
592
  addTypeDeps(t)
@@ -588,20 +632,142 @@ func (o *LoweringOwner) localFileAliases(
588
632
  }
589
633
  }
590
634
  }
635
+ addRuntimeTypeDeps = func(typ types.Type) {
636
+ if typ == nil {
637
+ return
638
+ }
639
+ if alias, ok := typ.(*types.Alias); ok {
640
+ addObject(alias.Obj(), true)
641
+ if args := alias.TypeArgs(); args != nil {
642
+ for t := range args.Types() {
643
+ addRuntimeTypeDeps(t)
644
+ }
645
+ }
646
+ addRuntimeTypeDeps(alias.Rhs())
647
+ return
648
+ }
649
+ if named, ok := types.Unalias(typ).(*types.Named); ok {
650
+ addObject(named.Obj(), true)
651
+ for method := range named.Methods() {
652
+ addObject(method, true)
653
+ }
654
+ methodSet := types.NewMethodSet(types.NewPointer(named))
655
+ for method := range methodSet.Methods() {
656
+ addObject(method.Obj(), true)
657
+ }
658
+ if args := named.TypeArgs(); args != nil {
659
+ for t := range args.Types() {
660
+ addRuntimeTypeDeps(t)
661
+ }
662
+ }
663
+ return
664
+ }
665
+ switch typed := types.Unalias(typ).Underlying().(type) {
666
+ case *types.Pointer:
667
+ addRuntimeTypeDeps(typed.Elem())
668
+ case *types.Slice:
669
+ addRuntimeTypeDeps(typed.Elem())
670
+ case *types.Array:
671
+ addRuntimeTypeDeps(typed.Elem())
672
+ case *types.Map:
673
+ addRuntimeTypeDeps(typed.Key())
674
+ addRuntimeTypeDeps(typed.Elem())
675
+ case *types.Chan:
676
+ addRuntimeTypeDeps(typed.Elem())
677
+ }
678
+ }
679
+ addRuntimeTypeOwnerDeps = func(typ types.Type) {
680
+ if typ == nil {
681
+ return
682
+ }
683
+ if alias, ok := typ.(*types.Alias); ok {
684
+ addObject(alias.Obj(), true)
685
+ if args := alias.TypeArgs(); args != nil {
686
+ for t := range args.Types() {
687
+ addRuntimeTypeOwnerDeps(t)
688
+ }
689
+ }
690
+ addRuntimeTypeOwnerDeps(alias.Rhs())
691
+ return
692
+ }
693
+ if named, ok := types.Unalias(typ).(*types.Named); ok {
694
+ addObject(named.Obj(), true)
695
+ if args := named.TypeArgs(); args != nil {
696
+ for t := range args.Types() {
697
+ addRuntimeTypeOwnerDeps(t)
698
+ }
699
+ }
700
+ return
701
+ }
702
+ switch typed := types.Unalias(typ).Underlying().(type) {
703
+ case *types.Pointer:
704
+ addRuntimeTypeOwnerDeps(typed.Elem())
705
+ case *types.Slice:
706
+ addRuntimeTypeOwnerDeps(typed.Elem())
707
+ case *types.Array:
708
+ addRuntimeTypeOwnerDeps(typed.Elem())
709
+ case *types.Map:
710
+ addRuntimeTypeOwnerDeps(typed.Key())
711
+ addRuntimeTypeOwnerDeps(typed.Elem())
712
+ case *types.Chan:
713
+ addRuntimeTypeOwnerDeps(typed.Elem())
714
+ }
715
+ }
591
716
  inspect := func(node ast.Node) bool {
592
717
  switch typed := node.(type) {
718
+ case *ast.ValueSpec:
719
+ if len(typed.Values) == 0 && typed.Type != nil {
720
+ addRuntimeTypeDeps(semPkg.source.TypesInfo.TypeOf(typed.Type))
721
+ }
593
722
  case *ast.Ident:
594
- addObject(semPkg.source.TypesInfo.Uses[typed])
723
+ if obj := semPkg.source.TypesInfo.Defs[typed]; obj != nil {
724
+ if _, ok := obj.(*types.PkgName); !ok {
725
+ name := safeIdentifier(obj.Name())
726
+ if name != "_" {
727
+ analysis.reservedNames[name] = true
728
+ }
729
+ }
730
+ }
731
+ if tv, ok := semPkg.source.TypesInfo.Types[typed]; ok && tv.IsValue() {
732
+ addObject(semPkg.source.TypesInfo.Uses[typed], true)
733
+ }
595
734
  addTypeDeps(semPkg.source.TypesInfo.TypeOf(typed))
596
735
  case *ast.SelectorExpr:
597
736
  if selection := semPkg.source.TypesInfo.Selections[typed]; selection != nil {
598
- addObject(selection.Obj())
737
+ switch selection.Kind() {
738
+ case types.FieldVal, types.MethodVal, types.MethodExpr:
739
+ addObject(selection.Obj(), true)
740
+ if selection.Kind() != types.FieldVal {
741
+ addRuntimeTypeOwnerDeps(selection.Recv())
742
+ }
743
+ default:
744
+ addObject(selection.Obj(), false)
745
+ }
746
+ addTypeDeps(selection.Obj().Type())
599
747
  } else if obj := semPkg.source.TypesInfo.Uses[typed.Sel]; obj != nil {
748
+ if tv, ok := semPkg.source.TypesInfo.Types[typed]; ok && tv.IsValue() {
749
+ addObject(obj, true)
750
+ }
600
751
  addTypeDeps(obj.Type())
601
752
  }
602
753
  if pointer, ok := types.Unalias(semPkg.source.TypesInfo.TypeOf(typed.X)).Underlying().(*types.Pointer); ok {
603
754
  addTypeDeps(pointer.Elem())
604
755
  }
756
+ case *ast.CompositeLit:
757
+ addRuntimeTypeDeps(semPkg.source.TypesInfo.TypeOf(typed))
758
+ addCompositeInterfaceValueDeps(semPkg.source.TypesInfo, typed, addRuntimeTypeDeps)
759
+ case *ast.CallExpr:
760
+ if ident, ok := ast.Unparen(typed.Fun).(*ast.Ident); ok && ident.Name == "new" {
761
+ for _, arg := range typed.Args {
762
+ addRuntimeTypeDeps(semPkg.source.TypesInfo.TypeOf(arg))
763
+ }
764
+ }
765
+ if ident, ok := ast.Unparen(typed.Fun).(*ast.Ident); ok && ident.Name == "make" && len(typed.Args) != 0 {
766
+ addRuntimeTypeDeps(semPkg.source.TypesInfo.TypeOf(typed.Args[0]))
767
+ }
768
+ addReflectTypeForRuntimeDeps(semPkg.source.TypesInfo, typed, addRuntimeTypeDeps)
769
+ addInterfaceArgumentRuntimeDeps(semPkg.source.TypesInfo, typed, addRuntimeTypeDeps)
770
+ addRuntimeTypeDeps(semPkg.source.TypesInfo.TypeOf(typed.Fun))
605
771
  }
606
772
  return true
607
773
  }
@@ -609,7 +775,163 @@ func (o *LoweringOwner) localFileAliases(
609
775
  for _, methodDecl := range associatedMethods {
610
776
  ast.Inspect(methodDecl, inspect)
611
777
  }
612
- return aliases, aliasSources, implicitImports
778
+ return analysis
779
+ }
780
+
781
+ func addInterfaceArgumentRuntimeDeps(
782
+ info *types.Info,
783
+ call *ast.CallExpr,
784
+ addRuntimeTypeDeps func(types.Type),
785
+ ) {
786
+ if info == nil || call == nil {
787
+ return
788
+ }
789
+ signature, _ := types.Unalias(info.TypeOf(call.Fun)).(*types.Signature)
790
+ if signature == nil || signature.Params() == nil {
791
+ return
792
+ }
793
+ params := signature.Params()
794
+ for idx, arg := range call.Args {
795
+ paramIdx := idx
796
+ if signature.Variadic() && paramIdx >= params.Len()-1 {
797
+ paramIdx = params.Len() - 1
798
+ }
799
+ if paramIdx < 0 || paramIdx >= params.Len() {
800
+ continue
801
+ }
802
+ paramType := params.At(paramIdx).Type()
803
+ if signature.Variadic() && idx >= params.Len()-1 {
804
+ if slice, ok := types.Unalias(paramType).Underlying().(*types.Slice); ok {
805
+ paramType = slice.Elem()
806
+ }
807
+ }
808
+ if typeIsInterface(paramType) {
809
+ addRuntimeTypeDeps(info.TypeOf(arg))
810
+ }
811
+ }
812
+ }
813
+
814
+ func addReflectTypeForRuntimeDeps(
815
+ info *types.Info,
816
+ call *ast.CallExpr,
817
+ addRuntimeTypeDeps func(types.Type),
818
+ ) {
819
+ if info == nil || call == nil || !isReflectTypeForExpr(info, call.Fun) {
820
+ return
821
+ }
822
+ switch typed := ast.Unparen(call.Fun).(type) {
823
+ case *ast.IndexExpr:
824
+ addRuntimeTypeDeps(info.TypeOf(typed.Index))
825
+ case *ast.IndexListExpr:
826
+ for _, index := range typed.Indices {
827
+ addRuntimeTypeDeps(info.TypeOf(index))
828
+ }
829
+ }
830
+ }
831
+
832
+ func isReflectTypeForExpr(info *types.Info, expr ast.Expr) bool {
833
+ var base ast.Expr
834
+ switch typed := ast.Unparen(expr).(type) {
835
+ case *ast.IndexExpr:
836
+ base = typed.X
837
+ case *ast.IndexListExpr:
838
+ base = typed.X
839
+ default:
840
+ return false
841
+ }
842
+ selector, ok := ast.Unparen(base).(*ast.SelectorExpr)
843
+ if !ok || selector.Sel.Name != "TypeFor" {
844
+ return false
845
+ }
846
+ ident, ok := ast.Unparen(selector.X).(*ast.Ident)
847
+ if !ok {
848
+ return false
849
+ }
850
+ pkgName, _ := info.Uses[ident].(*types.PkgName)
851
+ return pkgName != nil && pkgName.Imported() != nil && pkgName.Imported().Path() == "reflect"
852
+ }
853
+
854
+ func addCompositeInterfaceValueDeps(
855
+ info *types.Info,
856
+ lit *ast.CompositeLit,
857
+ addRuntimeTypeDeps func(types.Type),
858
+ ) {
859
+ if info == nil || lit == nil {
860
+ return
861
+ }
862
+ typ := types.Unalias(info.TypeOf(lit))
863
+ if pointer, ok := typ.Underlying().(*types.Pointer); ok {
864
+ typ = types.Unalias(pointer.Elem())
865
+ }
866
+ switch typed := typ.Underlying().(type) {
867
+ case *types.Array:
868
+ addCompositeElementsRuntimeDeps(info, lit.Elts, typed.Elem(), addRuntimeTypeDeps)
869
+ case *types.Slice:
870
+ addCompositeElementsRuntimeDeps(info, lit.Elts, typed.Elem(), addRuntimeTypeDeps)
871
+ case *types.Map:
872
+ for _, elt := range lit.Elts {
873
+ keyValue, ok := elt.(*ast.KeyValueExpr)
874
+ if !ok {
875
+ continue
876
+ }
877
+ if typeIsInterface(typed.Key()) {
878
+ addRuntimeTypeDeps(info.TypeOf(keyValue.Key))
879
+ }
880
+ if typeIsInterface(typed.Elem()) {
881
+ addRuntimeTypeDeps(info.TypeOf(keyValue.Value))
882
+ }
883
+ }
884
+ case *types.Struct:
885
+ nextField := 0
886
+ for _, elt := range lit.Elts {
887
+ fieldIdx := nextField
888
+ value := elt
889
+ if keyValue, ok := elt.(*ast.KeyValueExpr); ok {
890
+ value = keyValue.Value
891
+ if ident, ok := keyValue.Key.(*ast.Ident); ok {
892
+ for idx := range typed.NumFields() {
893
+ if typed.Field(idx).Name() == ident.Name {
894
+ fieldIdx = idx
895
+ break
896
+ }
897
+ }
898
+ }
899
+ } else {
900
+ nextField++
901
+ }
902
+ if fieldIdx < 0 || fieldIdx >= typed.NumFields() {
903
+ continue
904
+ }
905
+ if typeIsInterface(typed.Field(fieldIdx).Type()) {
906
+ addRuntimeTypeDeps(info.TypeOf(value))
907
+ }
908
+ }
909
+ }
910
+ }
911
+
912
+ func addCompositeElementsRuntimeDeps(
913
+ info *types.Info,
914
+ elements []ast.Expr,
915
+ elemType types.Type,
916
+ addRuntimeTypeDeps func(types.Type),
917
+ ) {
918
+ if !typeIsInterface(elemType) {
919
+ return
920
+ }
921
+ for _, elt := range elements {
922
+ if keyValue, ok := elt.(*ast.KeyValueExpr); ok {
923
+ elt = keyValue.Value
924
+ }
925
+ addRuntimeTypeDeps(info.TypeOf(elt))
926
+ }
927
+ }
928
+
929
+ func typeIsInterface(typ types.Type) bool {
930
+ if typ == nil {
931
+ return false
932
+ }
933
+ _, ok := types.Unalias(typ).Underlying().(*types.Interface)
934
+ return ok
613
935
  }
614
936
 
615
937
  func safeIdentifier(value string) string {
@@ -668,12 +990,16 @@ type lowerFileContext struct {
668
990
  importAliases map[string]string
669
991
  importPaths map[string]string
670
992
  importNames map[string]string
993
+ importObjects map[*types.PkgName]string
671
994
  sourcePath string
672
995
  localAliases map[types.Object]string
673
996
  lazyPackageVars map[types.Object]bool
674
997
  identAliases map[types.Object]string
998
+ identAliasRefs map[types.Object]bool
675
999
  tempNames *tempNameOwner
676
1000
  signature *types.Signature
1001
+ typeParams map[string]bool
1002
+ staticTypeParams map[string]bool
677
1003
  asyncFunction bool
678
1004
  functionTypeDepth int
679
1005
  deferState *loweredDeferState
@@ -694,6 +1020,30 @@ type tempNameOwner struct {
694
1020
  counters map[string]int
695
1021
  }
696
1022
 
1023
+ func (ctx lowerFileContext) canReferenceNamedType(named *types.Named) bool {
1024
+ if named == nil || named.Obj() == nil {
1025
+ return true
1026
+ }
1027
+ return ctx.canReferenceObjectPackage(named.Obj())
1028
+ }
1029
+
1030
+ func (ctx lowerFileContext) canReferenceObjectPackage(obj types.Object) bool {
1031
+ if obj == nil || obj.Pkg() == nil || ctx.semPkg == nil {
1032
+ return true
1033
+ }
1034
+ pkgPath := obj.Pkg().Path()
1035
+ if pkgPath == "" || pkgPath == ctx.semPkg.pkgPath {
1036
+ return true
1037
+ }
1038
+ if ctx.importPaths[pkgPath] != "" {
1039
+ return true
1040
+ }
1041
+ if ctx.localAliases[obj] != "" {
1042
+ return true
1043
+ }
1044
+ return false
1045
+ }
1046
+
697
1047
  func newTempNameOwner() *tempNameOwner {
698
1048
  return &tempNameOwner{counters: make(map[string]int)}
699
1049
  }
@@ -720,6 +1070,20 @@ func (ctx lowerFileContext) withIdentAliases(aliases map[types.Object]string) lo
720
1070
  return ctx
721
1071
  }
722
1072
 
1073
+ func (ctx lowerFileContext) withIdentRefAliases(aliases map[types.Object]string) lowerFileContext {
1074
+ if len(aliases) == 0 {
1075
+ return ctx
1076
+ }
1077
+ ctx = ctx.withIdentAliases(aliases)
1078
+ refs := make(map[types.Object]bool, len(ctx.identAliasRefs)+len(aliases))
1079
+ maps.Copy(refs, ctx.identAliasRefs)
1080
+ for obj := range aliases {
1081
+ refs[obj] = true
1082
+ }
1083
+ ctx.identAliasRefs = refs
1084
+ return ctx
1085
+ }
1086
+
723
1087
  func (o *tempNameOwner) next(prefix string) string {
724
1088
  idx := o.counters[prefix]
725
1089
  o.counters[prefix] = idx + 1
@@ -825,8 +1189,8 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
825
1189
  lazy := ctx.topLevel && ctx.lazyPackageVars[obj]
826
1190
  code := keyword + " " + declName + ": " + variableType + " = " + value
827
1191
  if lazy {
828
- keyword = "let"
829
- code = "let " + declName + ": " + variableType + " = undefined as unknown as " + variableType
1192
+ keyword = "var"
1193
+ code = "var " + declName + ": " + variableType + " = undefined as unknown as " + variableType
830
1194
  }
831
1195
  indexExport := ""
832
1196
  if ctx.topLevel && name.Name != "_" {
@@ -838,9 +1202,29 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
838
1202
  decls = append(decls, loweredDecl{code: code, indexExport: indexExport})
839
1203
  if lazy {
840
1204
  getterName := packageVarGetterName(name.Name)
841
- getterCode := "export function " + getterName + "(): " + variableType + " {\n\t" +
842
- "if (((" + declName + ") as any) === undefined) {\n\t\t" +
843
- declName + " = " + value + "\n\t}\n\treturn " + declName + "\n}"
1205
+ initName := packageVarInitName(name.Name)
1206
+ initIndexExport := ""
1207
+ if ast.IsExported(name.Name) {
1208
+ initIndexExport = initName
1209
+ }
1210
+ getterCode := "export function " + getterName + "(): " + variableType + " {\n\t"
1211
+ if strings.Contains(value, "await ") {
1212
+ initCode := "export async function " + initName + "(): globalThis.Promise<void> {\n\t" +
1213
+ "if (((" + declName + ") as any) === undefined) {\n\t\t" +
1214
+ declName + " = " + value + "\n\t}\n}"
1215
+ decls = append(decls, loweredDecl{code: initCode, indexExport: initIndexExport})
1216
+ decls = append(decls, loweredDecl{packageInitCall: initName + "()"})
1217
+ getterCode += "if (((" + declName + ") as any) === undefined) {\n\t\t" +
1218
+ "throw new Error(" + strconv.Quote("goscript package variable "+name.Name+" read before initialization") + ")\n\t}\n"
1219
+ } else {
1220
+ initCode := "export function " + initName + "(): void {\n\t" +
1221
+ "if (((" + declName + ") as any) === undefined) {\n\t\t" +
1222
+ declName + " = " + value + "\n\t}\n}"
1223
+ decls = append(decls, loweredDecl{code: initCode, indexExport: initIndexExport})
1224
+ getterCode += "if (((" + declName + ") as any) === undefined) {\n\t\t" +
1225
+ initName + "()\n\t}\n"
1226
+ }
1227
+ getterCode += "\treturn " + declName + "\n}"
844
1228
  getterIndexExport := ""
845
1229
  if ast.IsExported(name.Name) {
846
1230
  getterIndexExport = getterName
@@ -852,10 +1236,15 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
852
1236
  setterType := o.tsPackageVarSetterValueTypeFor(ctx, obj.Type())
853
1237
  setterTarget := declName
854
1238
  if ctx.model.needsVarRef[obj] {
855
- setterTarget += ".value"
1239
+ if lazy {
1240
+ setterTarget = packageVarGetterName(name.Name) + "().value"
1241
+ } else {
1242
+ setterTarget += ".value"
1243
+ }
856
1244
  }
857
- setterCode := "export function " + setterName + "(value: " + setterType + "): void {\n\t" +
858
- setterTarget + " = value\n}"
1245
+ setterValue := "__goscriptValue"
1246
+ setterCode := "export function " + setterName + "(" + setterValue + ": " + setterType + "): void {\n\t" +
1247
+ setterTarget + " = " + setterValue + "\n}"
859
1248
  setterIndexExport := ""
860
1249
  if ast.IsExported(name.Name) {
861
1250
  setterIndexExport = setterName
@@ -909,6 +1298,9 @@ func initializerMayHaveRuntimeEffects(ctx lowerFileContext, expr ast.Expr) bool
909
1298
  }
910
1299
  switch typed := node.(type) {
911
1300
  case *ast.CallExpr:
1301
+ if isEffectFreePackageInitializerCall(ctx, typed) {
1302
+ return true
1303
+ }
912
1304
  if callTargetSignature(ctx, typed.Fun) != nil {
913
1305
  hasEffects = true
914
1306
  return false
@@ -924,23 +1316,322 @@ func initializerMayHaveRuntimeEffects(ctx lowerFileContext, expr ast.Expr) bool
924
1316
  return hasEffects
925
1317
  }
926
1318
 
927
- func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage) map[types.Object]bool {
1319
+ func isEffectFreePackageInitializerCall(ctx lowerFileContext, call *ast.CallExpr) bool {
1320
+ if call == nil {
1321
+ return false
1322
+ }
1323
+ if isEffectFreePackageInitializerBuiltin(ctx, call.Fun) {
1324
+ return true
1325
+ }
1326
+ if isReflectTypeOfCall(ctx, call) {
1327
+ return true
1328
+ }
1329
+ if isReflectTypeForCall(ctx, call) {
1330
+ return true
1331
+ }
1332
+ if isMathBigNewIntCall(ctx, call) {
1333
+ return true
1334
+ }
1335
+ selector, ok := ast.Unparen(call.Fun).(*ast.SelectorExpr)
1336
+ if !ok || selector.Sel.Name != "Elem" {
1337
+ return false
1338
+ }
1339
+ receiver, ok := ast.Unparen(selector.X).(*ast.CallExpr)
1340
+ return ok && isReflectTypeOfCall(ctx, receiver)
1341
+ }
1342
+
1343
+ func isEffectFreePackageInitializerBuiltin(ctx lowerFileContext, expr ast.Expr) bool {
1344
+ ident, ok := expr.(*ast.Ident)
1345
+ if !ok {
1346
+ return false
1347
+ }
1348
+ if ident.Name != "make" && ident.Name != "new" {
1349
+ return false
1350
+ }
1351
+ _, ok = objectForIdent(ctx, ident).(*types.Builtin)
1352
+ return ok
1353
+ }
1354
+
1355
+ func isReflectTypeOfCall(ctx lowerFileContext, call *ast.CallExpr) bool {
1356
+ selector, ok := ast.Unparen(call.Fun).(*ast.SelectorExpr)
1357
+ if !ok || selector.Sel.Name != "TypeOf" {
1358
+ return false
1359
+ }
1360
+ ident, ok := ast.Unparen(selector.X).(*ast.Ident)
1361
+ if !ok {
1362
+ return false
1363
+ }
1364
+ pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName)
1365
+ return pkgName != nil && pkgName.Imported() != nil && pkgName.Imported().Path() == "reflect"
1366
+ }
1367
+
1368
+ func isReflectTypeForCall(ctx lowerFileContext, call *ast.CallExpr) bool {
1369
+ fun := ast.Unparen(call.Fun)
1370
+ switch typed := fun.(type) {
1371
+ case *ast.IndexExpr:
1372
+ fun = ast.Unparen(typed.X)
1373
+ case *ast.IndexListExpr:
1374
+ fun = ast.Unparen(typed.X)
1375
+ }
1376
+ selector, ok := fun.(*ast.SelectorExpr)
1377
+ if !ok || selector.Sel.Name != "TypeFor" {
1378
+ return false
1379
+ }
1380
+ ident, ok := ast.Unparen(selector.X).(*ast.Ident)
1381
+ if !ok {
1382
+ return false
1383
+ }
1384
+ pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName)
1385
+ return pkgName != nil && pkgName.Imported() != nil && pkgName.Imported().Path() == "reflect"
1386
+ }
1387
+
1388
+ func isMathBigNewIntCall(ctx lowerFileContext, call *ast.CallExpr) bool {
1389
+ selector, ok := ast.Unparen(call.Fun).(*ast.SelectorExpr)
1390
+ if !ok || selector.Sel.Name != "NewInt" {
1391
+ return false
1392
+ }
1393
+ ident, ok := ast.Unparen(selector.X).(*ast.Ident)
1394
+ if !ok {
1395
+ return false
1396
+ }
1397
+ pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName)
1398
+ return pkgName != nil && pkgName.Imported() != nil && pkgName.Imported().Path() == "math/big"
1399
+ }
1400
+
1401
+ func packageDeclFiles(semPkg *semanticPackage) map[types.Object]string {
1402
+ if semPkg == nil || semPkg.source == nil {
1403
+ return nil
1404
+ }
1405
+ declFiles := make(map[types.Object]string)
1406
+ for _, decl := range semPkg.declarations {
1407
+ if decl.object != nil && decl.position.file != "" {
1408
+ declFiles[decl.object] = decl.position.file
1409
+ }
1410
+ }
1411
+ return declFiles
1412
+ }
1413
+
1414
+ func packageOutputNames(semPkg *semanticPackage) map[string]string {
1415
+ if semPkg == nil || semPkg.source == nil {
1416
+ return nil
1417
+ }
1418
+ outputNames := make(map[string]string, len(semPkg.source.Syntax))
1419
+ for idx, syntax := range semPkg.source.Syntax {
1420
+ outputSourcePath := sourceFilePath(semPkg, idx, syntax)
1421
+ outputNames[outputSourcePath] = sourceOutputName(outputSourcePath)
1422
+ }
1423
+ return outputNames
1424
+ }
1425
+
1426
+ func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage, declFiles map[types.Object]string) map[types.Object]bool {
928
1427
  if semPkg == nil || semPkg.source == nil {
929
1428
  return nil
930
1429
  }
931
- declFiles := make(map[types.Object]string)
932
- for _, decl := range semPkg.declarations {
933
- if decl.object != nil && decl.position.file != "" {
934
- declFiles[decl.object] = decl.position.file
935
- }
1430
+ varOrder := make(map[types.Object]int)
1431
+ for idx, obj := range semPkg.initOrder {
1432
+ varOrder[obj] = idx
1433
+ }
1434
+ funcRefs := packageVarsReferencedFromOtherFileTopLevelCalls(semPkg, declFiles)
1435
+ lazy := make(map[types.Object]bool)
1436
+ for idx, file := range semPkg.source.Syntax {
1437
+ sourcePath := sourceFilePath(semPkg, idx, file)
1438
+ for _, decl := range file.Decls {
1439
+ genDecl, ok := decl.(*ast.GenDecl)
1440
+ if !ok || genDecl.Tok != token.VAR {
1441
+ continue
1442
+ }
1443
+ for _, spec := range genDecl.Specs {
1444
+ valueSpec, ok := spec.(*ast.ValueSpec)
1445
+ if !ok {
1446
+ continue
1447
+ }
1448
+ for valueIdx, name := range valueSpec.Names {
1449
+ obj, _ := semPkg.source.TypesInfo.Defs[name].(*types.Var)
1450
+ if obj == nil {
1451
+ continue
1452
+ }
1453
+ if valueIdx < len(valueSpec.Values) &&
1454
+ initializerReferencesLaterPackageVar(semPkg, varOrder, obj, valueSpec.Values[valueIdx]) {
1455
+ lazy[obj] = true
1456
+ continue
1457
+ }
1458
+ if valueIdx < len(valueSpec.Values) &&
1459
+ initializerReferencesOtherFileObject(semPkg, declFiles, sourcePath, valueSpec.Values[valueIdx]) {
1460
+ lazy[obj] = true
1461
+ continue
1462
+ }
1463
+ if valueIdx < len(valueSpec.Values) &&
1464
+ initializerCallsFunctionReferencingLaterPackageVar(semPkg, varOrder, obj, valueSpec.Values[valueIdx]) {
1465
+ lazy[obj] = true
1466
+ continue
1467
+ }
1468
+ if valueIdx >= len(valueSpec.Values) &&
1469
+ zeroValueReferencesOtherFileObject(semPkg, declFiles, sourcePath, obj.Type()) {
1470
+ lazy[obj] = true
1471
+ continue
1472
+ }
1473
+ if funcRefs[obj] &&
1474
+ (valueIdx >= len(valueSpec.Values) ||
1475
+ !initializerMayHaveRuntimeEffects(lowerFileContext{semPkg: semPkg}, valueSpec.Values[valueIdx])) {
1476
+ lazy[obj] = true
1477
+ }
1478
+ }
1479
+ }
1480
+ }
1481
+ }
1482
+ return lazy
1483
+ }
1484
+
1485
+ func packageVarsReferencedFromOtherFileTopLevelCalls(
1486
+ semPkg *semanticPackage,
1487
+ declFiles map[types.Object]string,
1488
+ ) map[*types.Var]bool {
1489
+ refs := make(map[*types.Var]bool)
1490
+ if semPkg == nil || semPkg.source == nil || semPkg.source.TypesInfo == nil {
1491
+ return refs
1492
+ }
1493
+ var collectFuncRefs func(rootSource string, fn *types.Func, seen map[*types.Func]bool)
1494
+ collectFuncRefs = func(rootSource string, fn *types.Func, seen map[*types.Func]bool) {
1495
+ if fn == nil || seen[fn] {
1496
+ return
1497
+ }
1498
+ seen[fn] = true
1499
+ decl := functionDeclForObject(semPkg, fn)
1500
+ if decl == nil || decl.Body == nil {
1501
+ return
1502
+ }
1503
+ ast.Inspect(decl.Body, func(node ast.Node) bool {
1504
+ switch typed := node.(type) {
1505
+ case *ast.Ident:
1506
+ obj, _ := semPkg.source.TypesInfo.Uses[typed].(*types.Var)
1507
+ if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != semPkg.pkgPath {
1508
+ return true
1509
+ }
1510
+ if declFiles[obj] != "" && declFiles[obj] != rootSource {
1511
+ refs[obj] = true
1512
+ }
1513
+ case *ast.CallExpr:
1514
+ called := calledFunction(semPkg.source, typed.Fun)
1515
+ if called != nil && called.Pkg() != nil && called.Pkg().Path() == semPkg.pkgPath {
1516
+ collectFuncRefs(rootSource, called, seen)
1517
+ }
1518
+ }
1519
+ return true
1520
+ })
1521
+ }
1522
+ for _, file := range semPkg.source.Syntax {
1523
+ sourcePath := sourcePos(semPkg.source, file.Pos()).file
1524
+ for _, decl := range file.Decls {
1525
+ switch typed := decl.(type) {
1526
+ case *ast.GenDecl:
1527
+ if typed.Tok != token.VAR {
1528
+ continue
1529
+ }
1530
+ for _, spec := range typed.Specs {
1531
+ valueSpec, ok := spec.(*ast.ValueSpec)
1532
+ if !ok {
1533
+ continue
1534
+ }
1535
+ for _, value := range valueSpec.Values {
1536
+ collectTopLevelRefs(semPkg, declFiles, refs, sourcePath, value, collectFuncRefs)
1537
+ }
1538
+ }
1539
+ case *ast.FuncDecl:
1540
+ if typed.Name.Name == "init" && typed.Body != nil {
1541
+ collectTopLevelRefs(semPkg, declFiles, refs, sourcePath, typed.Body, collectFuncRefs)
1542
+ }
1543
+ }
1544
+ }
1545
+ }
1546
+ return refs
1547
+ }
1548
+
1549
+ func collectTopLevelRefs(
1550
+ semPkg *semanticPackage,
1551
+ declFiles map[types.Object]string,
1552
+ refs map[*types.Var]bool,
1553
+ sourcePath string,
1554
+ node ast.Node,
1555
+ collectFuncRefs func(string, *types.Func, map[*types.Func]bool),
1556
+ ) {
1557
+ ast.Inspect(node, func(node ast.Node) bool {
1558
+ switch typed := node.(type) {
1559
+ case *ast.Ident:
1560
+ obj, _ := semPkg.source.TypesInfo.Uses[typed].(*types.Var)
1561
+ if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != semPkg.pkgPath {
1562
+ return true
1563
+ }
1564
+ if declFiles[obj] != "" && declFiles[obj] != sourcePath {
1565
+ refs[obj] = true
1566
+ }
1567
+ case *ast.CallExpr:
1568
+ called := calledFunction(semPkg.source, typed.Fun)
1569
+ if called == nil || called.Pkg() == nil || called.Pkg().Path() != semPkg.pkgPath {
1570
+ return true
1571
+ }
1572
+ collectFuncRefs(sourcePath, called, make(map[*types.Func]bool))
1573
+ }
1574
+ return true
1575
+ })
1576
+ }
1577
+
1578
+ func (o *LoweringOwner) packageVarIsLazy(ctx lowerFileContext, obj *types.Var) bool {
1579
+ if obj == nil {
1580
+ return false
1581
+ }
1582
+ if ctx.lazyPackageVars[obj] {
1583
+ return true
1584
+ }
1585
+ if ctx.model == nil || obj.Pkg() == nil {
1586
+ return false
1587
+ }
1588
+ semPkg := ctx.model.packages[obj.Pkg().Path()]
1589
+ if semPkg == nil {
1590
+ return false
1591
+ }
1592
+ for lazyObj := range o.lazyPackageVars(semPkg, packageDeclFiles(semPkg)) {
1593
+ if lazyObj != nil && lazyObj.Name() == obj.Name() &&
1594
+ lazyObj.Pkg() != nil && lazyObj.Pkg().Path() == obj.Pkg().Path() {
1595
+ return true
1596
+ }
1597
+ }
1598
+ return false
1599
+ }
1600
+
1601
+ func (o *LoweringOwner) packageVarNameIsLazy(ctx lowerFileContext, pkgPath, name string) bool {
1602
+ if ctx.model == nil || pkgPath == "" || name == "" {
1603
+ return false
1604
+ }
1605
+ semPkg := ctx.model.packages[pkgPath]
1606
+ if semPkg == nil {
1607
+ return false
1608
+ }
1609
+ for lazyObj := range o.lazyPackageVars(semPkg, packageDeclFiles(semPkg)) {
1610
+ if lazyObj != nil && lazyObj.Name() == name {
1611
+ return true
1612
+ }
1613
+ }
1614
+ return false
1615
+ }
1616
+
1617
+ func (o *LoweringOwner) packageVarHasAsyncLazyInit(ctx lowerFileContext, obj types.Object) bool {
1618
+ varObj, _ := obj.(*types.Var)
1619
+ if varObj == nil || varObj.Pkg() == nil {
1620
+ return false
1621
+ }
1622
+ return o.packageVarNameHasAsyncLazyInit(ctx, varObj.Pkg().Path(), varObj.Name())
1623
+ }
1624
+
1625
+ func (o *LoweringOwner) packageVarNameHasAsyncLazyInit(ctx lowerFileContext, pkgPath, name string) bool {
1626
+ if ctx.model == nil || pkgPath == "" || name == "" {
1627
+ return false
936
1628
  }
937
- varOrder := make(map[types.Object]int)
938
- for idx, obj := range semPkg.initOrder {
939
- varOrder[obj] = idx
1629
+ semPkg := ctx.model.packages[pkgPath]
1630
+ if semPkg == nil || semPkg.source == nil {
1631
+ return false
940
1632
  }
941
- lazy := make(map[types.Object]bool)
942
- for idx, file := range semPkg.source.Syntax {
943
- sourcePath := sourceFilePath(semPkg, idx, file)
1633
+ initCtx := lowerFileContext{model: ctx.model, semPkg: semPkg, topLevel: true}
1634
+ for _, file := range semPkg.source.Syntax {
944
1635
  for _, decl := range file.Decls {
945
1636
  genDecl, ok := decl.(*ast.GenDecl)
946
1637
  if !ok || genDecl.Tok != token.VAR {
@@ -951,30 +1642,51 @@ func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage) map[types.Objec
951
1642
  if !ok {
952
1643
  continue
953
1644
  }
954
- for valueIdx, name := range valueSpec.Names {
955
- obj, _ := semPkg.source.TypesInfo.Defs[name].(*types.Var)
956
- if obj == nil {
957
- continue
958
- }
959
- if valueIdx < len(valueSpec.Values) &&
960
- initializerReferencesOtherFileObject(semPkg, declFiles, sourcePath, valueSpec.Values[valueIdx]) {
961
- lazy[obj] = true
962
- continue
963
- }
964
- if valueIdx < len(valueSpec.Values) &&
965
- initializerCallsFunctionReferencingLaterPackageVar(semPkg, varOrder, obj, valueSpec.Values[valueIdx]) {
966
- lazy[obj] = true
1645
+ for idx, ident := range valueSpec.Names {
1646
+ if ident.Name != name || idx >= len(valueSpec.Values) {
967
1647
  continue
968
1648
  }
969
- if valueIdx >= len(valueSpec.Values) &&
970
- zeroValueReferencesOtherFileObject(semPkg, declFiles, sourcePath, obj.Type()) {
971
- lazy[obj] = true
972
- }
1649
+ return o.topLevelInitializerNeedsAwait(initCtx, valueSpec.Values[idx])
973
1650
  }
974
1651
  }
975
1652
  }
976
1653
  }
977
- return lazy
1654
+ return false
1655
+ }
1656
+
1657
+ func initializerReferencesLaterPackageVar(
1658
+ semPkg *semanticPackage,
1659
+ varOrder map[types.Object]int,
1660
+ current types.Object,
1661
+ expr ast.Expr,
1662
+ ) bool {
1663
+ currentIdx, ok := varOrder[current]
1664
+ if !ok {
1665
+ return false
1666
+ }
1667
+ references := false
1668
+ ast.Inspect(expr, func(node ast.Node) bool {
1669
+ if references {
1670
+ return false
1671
+ }
1672
+ if _, ok := node.(*ast.FuncLit); ok {
1673
+ return false
1674
+ }
1675
+ ident, ok := node.(*ast.Ident)
1676
+ if !ok {
1677
+ return true
1678
+ }
1679
+ obj, ok := semPkg.source.TypesInfo.Uses[ident].(*types.Var)
1680
+ if !ok || obj.Pkg() == nil || obj.Pkg().Path() != semPkg.pkgPath {
1681
+ return true
1682
+ }
1683
+ if idx, ok := varOrder[obj]; ok && idx > currentIdx {
1684
+ references = true
1685
+ return false
1686
+ }
1687
+ return true
1688
+ })
1689
+ return references
978
1690
  }
979
1691
 
980
1692
  func initializerCallsFunctionReferencingLaterPackageVar(
@@ -1164,7 +1876,7 @@ func (o *LoweringOwner) lowerTupleValueSpec(
1164
1876
  tupleExpr := tempName
1165
1877
  if lazyTuple {
1166
1878
  tupleGetterName := packageVarGetterName(tempName)
1167
- decls = append(decls, loweredDecl{code: "let " + tempName + ": any = undefined as any"})
1879
+ decls = append(decls, loweredDecl{code: "var " + tempName + ": any = undefined as any"})
1168
1880
  decls = append(decls, loweredDecl{code: "function " + tupleGetterName + "(): any {\n\t" +
1169
1881
  "if (((" + tempName + ") as any) === undefined) {\n\t\t" +
1170
1882
  tempName + " = " + right + "\n\t}\n\treturn " + tempName + "\n}"})
@@ -1189,8 +1901,8 @@ func (o *LoweringOwner) lowerTupleValueSpec(
1189
1901
  code := keyword + " " + o.lowerIdent(ctx, name, true) + ": " + variableType + " = " + value
1190
1902
  lazy := lazyTuple || ctx.topLevel && ctx.lazyPackageVars[obj]
1191
1903
  if lazy {
1192
- keyword = "let"
1193
- code = "let " + o.lowerIdent(ctx, name, true) + ": " + variableType + " = undefined as unknown as " + variableType
1904
+ keyword = "var"
1905
+ code = "var " + o.lowerIdent(ctx, name, true) + ": " + variableType + " = undefined as unknown as " + variableType
1194
1906
  }
1195
1907
  indexExport := ""
1196
1908
  if ctx.topLevel {
@@ -1223,7 +1935,7 @@ func lowerConstantValue(value constant.Value) (string, bool) {
1223
1935
  case constant.Bool:
1224
1936
  return strconv.FormatBool(constant.BoolVal(value)), true
1225
1937
  case constant.String:
1226
- return strconv.Quote(constant.StringVal(value)), true
1938
+ return lowerGoStringLiteral(constant.StringVal(value)), true
1227
1939
  case constant.Int:
1228
1940
  if intValue, ok := constant.Int64Val(value); ok {
1229
1941
  return strconv.FormatInt(intValue, 10), true
@@ -1237,7 +1949,7 @@ func lowerConstantValue(value constant.Value) (string, bool) {
1237
1949
  case constant.Complex:
1238
1950
  real := constant.Real(value).ExactString()
1239
1951
  imag := constant.Imag(value).ExactString()
1240
- return "({ real: " + real + ", imag: " + imag + " })", true
1952
+ return "$.complex(" + real + ", " + imag + ")", true
1241
1953
  default:
1242
1954
  return "", false
1243
1955
  }
@@ -1333,6 +2045,13 @@ func byteSliceLiteral(data []byte) string {
1333
2045
  return "new Uint8Array([" + strings.Join(values, ", ") + "])"
1334
2046
  }
1335
2047
 
2048
+ func lowerGoStringLiteral(value string) string {
2049
+ if utf8.ValidString(value) {
2050
+ return strconv.Quote(value)
2051
+ }
2052
+ return "$.bytesToString(" + byteSliceLiteral([]byte(value)) + ")"
2053
+ }
2054
+
1336
2055
  func (o *LoweringOwner) lowerTypeSpec(ctx lowerFileContext, spec *ast.TypeSpec) (loweredDecl, []Diagnostic) {
1337
2056
  obj, _ := ctx.semPkg.source.TypesInfo.Defs[spec.Name].(*types.TypeName)
1338
2057
  if obj == nil {
@@ -1372,12 +2091,13 @@ func (o *LoweringOwner) lowerTypeSpec(ctx lowerFileContext, spec *ast.TypeSpec)
1372
2091
  if signature, ok := named.Underlying().(*types.Signature); ok {
1373
2092
  loweredType = o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
1374
2093
  }
1375
- code := "type " + semType.name + " = " + loweredType
2094
+ typeName := safeIdentifier(semType.name)
2095
+ code := "type " + typeName + " = " + loweredType
1376
2096
  typeIndexExport := ""
1377
2097
  if ctx.topLevel {
1378
2098
  code = "export " + code
1379
2099
  if ast.IsExported(semType.name) {
1380
- typeIndexExport = semType.name
2100
+ typeIndexExport = typeName
1381
2101
  }
1382
2102
  }
1383
2103
  return loweredDecl{code: code, typeIndexExport: typeIndexExport}, nil
@@ -1385,18 +2105,19 @@ func (o *LoweringOwner) lowerTypeSpec(ctx lowerFileContext, spec *ast.TypeSpec)
1385
2105
 
1386
2106
  func (o *LoweringOwner) lowerInterfaceType(ctx lowerFileContext, semType *semanticType, iface *types.Interface) loweredDecl {
1387
2107
  iface.Complete()
1388
- code := "type " + semType.name + " = " + o.tsInterfaceType(ctx, iface)
2108
+ typeName := safeIdentifier(semType.name)
2109
+ code := "type " + typeName + " = " + o.tsInterfaceType(ctx, iface)
1389
2110
  typeIndexExport := ""
1390
2111
  if ctx.topLevel {
1391
2112
  code = "export " + code
1392
2113
  if ast.IsExported(semType.name) {
1393
- typeIndexExport = semType.name
2114
+ typeIndexExport = typeName
1394
2115
  }
1395
2116
  }
1396
2117
  code = code + "\n\n" + o.runtimeOwner.QualifiedHelper(RuntimeHelperRegisterInterfaceType) +
1397
2118
  "(\n\t" + strconv.Quote(runtimeNamedTypeName(semType.named)) +
1398
2119
  ",\n\tnull,\n\t" + o.runtimeMethodSignatures(iface) + "\n)"
1399
- return loweredDecl{code: code, typeIndexExport: typeIndexExport}
2120
+ return loweredDecl{code: code, typeIndexExport: typeIndexExport, sideEffect: true}
1400
2121
  }
1401
2122
 
1402
2123
  func (o *LoweringOwner) tsInterfaceType(ctx lowerFileContext, iface *types.Interface) string {
@@ -1407,7 +2128,7 @@ func (o *LoweringOwner) tsInterfaceType(ctx lowerFileContext, iface *types.Inter
1407
2128
  for method := range iface.Methods() {
1408
2129
  methods = append(methods, o.tsMethodSignature(ctx, method))
1409
2130
  }
1410
- return "null | {\n\t" + strings.Join(methods, "\n\t") + "\n}"
2131
+ return "{\n\t" + strings.Join(methods, "\n\t") + "\n}"
1411
2132
  }
1412
2133
 
1413
2134
  func (o *LoweringOwner) tsMethodSignature(ctx lowerFileContext, method *types.Func) string {
@@ -1417,7 +2138,7 @@ func (o *LoweringOwner) tsMethodSignature(ctx lowerFileContext, method *types.Fu
1417
2138
  }
1418
2139
  async := o.functionAsync(ctx, method)
1419
2140
  return method.Name() + "(" + o.tsSignatureParamsFor(ctx, signature, async) + "): " +
1420
- asyncResultType(o.tsSignatureResultFor(ctx, signature), async)
2141
+ asyncCompatibleMethodResultType(o.tsSignatureResultFor(ctx, signature), async)
1421
2142
  }
1422
2143
 
1423
2144
  func (o *LoweringOwner) runtimeMethodSignatures(iface *types.Interface) string {
@@ -1478,11 +2199,15 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
1478
2199
  lowered := &loweredStruct{
1479
2200
  exported: ctx.topLevel,
1480
2201
  indexExported: ctx.topLevel && ast.IsExported(semType.name),
1481
- name: semType.name,
2202
+ name: safeIdentifier(semType.name),
1482
2203
  typeName: runtimeNamedTypeName(semType.named),
1483
2204
  cloneMethod: "clone",
1484
2205
  }
1485
2206
  for idx, field := range semType.fields {
2207
+ structValue := isStructValueType(field.typ)
2208
+ if named := namedStructType(field.typ); named != nil && crossPackageUnexportedNamedType(ctx, named) {
2209
+ structValue = false
2210
+ }
1486
2211
  fieldName := tsStructFieldName(field.name, idx)
1487
2212
  runtimeName := ""
1488
2213
  if fieldName != field.name {
@@ -1496,11 +2221,18 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
1496
2221
  runtimeType: o.runtimeTypeInfoExpr(field.typ),
1497
2222
  doc: field.doc,
1498
2223
  tag: field.tag,
1499
- structValue: isStructValueType(field.typ),
2224
+ structValue: structValue,
2225
+ arrayValue: isArrayType(field.typ),
1500
2226
  })
1501
2227
  }
1502
2228
 
1503
2229
  methodDecls := o.methodDeclsForType(ctx, semType.named)
2230
+ explicitMethods := make(map[string]bool, len(methodDecls))
2231
+ for _, methodDecl := range methodDecls {
2232
+ if methodDecl != nil {
2233
+ explicitMethods[methodDecl.Name.Name] = true
2234
+ }
2235
+ }
1504
2236
  var diagnostics []Diagnostic
1505
2237
  for _, methodDecl := range methodDecls {
1506
2238
  method, methodDiagnostics := o.lowerFuncDecl(ctx, methodDecl)
@@ -1512,9 +2244,121 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
1512
2244
  lowered.methods = append(lowered.methods, *method)
1513
2245
  }
1514
2246
  }
2247
+ for _, field := range semType.fields {
2248
+ methods := o.lowerEmbeddedMethodForwarders(ctx, field, explicitMethods)
2249
+ lowered.methods = append(lowered.methods, methods...)
2250
+ }
1515
2251
  return lowered, diagnostics
1516
2252
  }
1517
2253
 
2254
+ func (o *LoweringOwner) lowerEmbeddedMethodForwarders(
2255
+ ctx lowerFileContext,
2256
+ field semanticField,
2257
+ explicitMethods map[string]bool,
2258
+ ) []loweredFunction {
2259
+ if !field.embedded {
2260
+ return nil
2261
+ }
2262
+ methodSetType := field.typ
2263
+ if named := namedStructType(field.typ); named != nil {
2264
+ methodSetType = types.NewPointer(field.typ)
2265
+ } else if pointerToNamedStructType(field.typ) != nil {
2266
+ methodSetType = field.typ
2267
+ } else if _, ok := types.Unalias(field.typ).Underlying().(*types.Interface); !ok {
2268
+ return nil
2269
+ }
2270
+ methodSet := types.NewMethodSet(methodSetType)
2271
+ if methodSet.Len() == 0 {
2272
+ return nil
2273
+ }
2274
+ var methods []loweredFunction
2275
+ for selection := range methodSet.Methods() {
2276
+ method, _ := selection.Obj().(*types.Func)
2277
+ if method == nil || explicitMethods[method.Name()] {
2278
+ continue
2279
+ }
2280
+ if !ast.IsExported(method.Name()) && method.Pkg() != nil && method.Pkg().Path() != ctx.semPkg.pkgPath {
2281
+ continue
2282
+ }
2283
+ signature, _ := method.Type().(*types.Signature)
2284
+ if signature == nil {
2285
+ continue
2286
+ }
2287
+ async := o.functionAsync(ctx, method)
2288
+ targetType := o.tsEmbeddedForwarderTargetType(ctx, field.typ)
2289
+ lowered := loweredFunction{
2290
+ async: async,
2291
+ name: methodMemberName(method.Name()),
2292
+ runtimeName: method.Name(),
2293
+ result: asyncResultType("any", async),
2294
+ deferState: &loweredDeferState{},
2295
+ }
2296
+ args := make([]string, 0, signature.Params().Len())
2297
+ for idx := range signature.Params().Len() {
2298
+ param := signature.Params().At(idx)
2299
+ name := safeParamName(param, idx)
2300
+ args = append(args, name)
2301
+ lowered.params = append(lowered.params, loweredParam{name: name, typ: "any"})
2302
+ }
2303
+ target := o.embeddedForwarderTargetExpr(ctx, field, selection, targetType)
2304
+ call := target + "." + method.Name() + "(" + strings.Join(args, ", ") + ")"
2305
+ if async {
2306
+ call = "await " + call
2307
+ }
2308
+ lowered.body = []loweredStmt{{text: "return " + call}}
2309
+ methods = append(methods, lowered)
2310
+ explicitMethods[method.Name()] = true
2311
+ }
2312
+ return methods
2313
+ }
2314
+
2315
+ func (o *LoweringOwner) embeddedForwarderTargetExpr(
2316
+ ctx lowerFileContext,
2317
+ field semanticField,
2318
+ selection *types.Selection,
2319
+ targetType string,
2320
+ ) string {
2321
+ pointerValue := o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue)
2322
+ expr := pointerValue + "<" + targetType + ">(this." + tsStructFieldName(field.name, 0) + ")"
2323
+ if selection == nil || len(selection.Index()) <= 1 {
2324
+ return expr
2325
+ }
2326
+
2327
+ typ := field.typ
2328
+ for _, index := range selection.Index()[:len(selection.Index())-1] {
2329
+ structType, ok := types.Unalias(derefPointerType(typ)).Underlying().(*types.Struct)
2330
+ if !ok || index < 0 || index >= structType.NumFields() {
2331
+ return expr
2332
+ }
2333
+ field := structType.Field(index)
2334
+ expr += "." + tsStructFieldName(field.Name(), index)
2335
+ typ = field.Type()
2336
+ expr = o.embeddedForwarderSelectableExpr(ctx, typ, expr)
2337
+ }
2338
+ return expr
2339
+ }
2340
+
2341
+ func (o *LoweringOwner) embeddedForwarderSelectableExpr(ctx lowerFileContext, typ types.Type, expr string) string {
2342
+ pointerValue := o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue)
2343
+ if named := pointerToNamedStructType(typ); named != nil {
2344
+ return pointerValue + "<any>(" + expr + ")"
2345
+ }
2346
+ if _, ok := types.Unalias(typ).Underlying().(*types.Interface); ok {
2347
+ return pointerValue + "<any>(" + expr + ")"
2348
+ }
2349
+ return expr
2350
+ }
2351
+
2352
+ func (o *LoweringOwner) tsEmbeddedForwarderTargetType(ctx lowerFileContext, typ types.Type) string {
2353
+ if named := pointerToNamedStructType(typ); named != nil {
2354
+ return o.namedTypeExpr(ctx, named)
2355
+ }
2356
+ if named := namedStructType(typ); named != nil {
2357
+ return o.namedTypeExpr(ctx, named)
2358
+ }
2359
+ return "Exclude<" + o.tsStructFieldTypeFor(ctx, typ) + ", null>"
2360
+ }
2361
+
1518
2362
  func (o *LoweringOwner) methodDeclsForType(ctx lowerFileContext, named *types.Named) []*ast.FuncDecl {
1519
2363
  if named == nil {
1520
2364
  return nil
@@ -1574,7 +2418,8 @@ func (o *LoweringOwner) lowerNamedReceiverMethodDecl(
1574
2418
  return nil, nil
1575
2419
  }
1576
2420
  async := o.functionAsync(ctx, fnObj)
1577
- resultCtx := ctx.withAsyncFunction(async)
2421
+ functionCtx := ctx.withSignature(signature)
2422
+ resultCtx := functionCtx.withAsyncFunction(async)
1578
2423
  result := o.tsSignatureResultFor(resultCtx, signature)
1579
2424
  receiverName := "recv"
1580
2425
  if len(decl.Recv.List) != 0 && len(decl.Recv.List[0].Names) != 0 {
@@ -1634,7 +2479,11 @@ func (o *LoweringOwner) lowerFuncDecl(ctx lowerFileContext, decl *ast.FuncDecl)
1634
2479
  return nil, nil
1635
2480
  }
1636
2481
  async := o.functionAsync(ctx, fnObj)
1637
- resultCtx := ctx.withAsyncFunction(async)
2482
+ if decl.Name.Name == "main" {
2483
+ async = true
2484
+ }
2485
+ functionCtx := ctx.withSignature(signature)
2486
+ resultCtx := functionCtx.withAsyncFunction(async)
1638
2487
  result := o.tsSignatureResultFor(resultCtx, signature)
1639
2488
  deferState := &loweredDeferState{}
1640
2489
  name := safeIdentifier(decl.Name.Name)
@@ -1659,9 +2508,10 @@ func (o *LoweringOwner) lowerFuncDecl(ctx lowerFileContext, decl *ast.FuncDecl)
1659
2508
  runtimeName: runtimeName,
1660
2509
  result: asyncResultType(result, async),
1661
2510
  deferState: deferState,
1662
- namedResults: o.lowerNamedResults(ctx, signature),
2511
+ namedResults: o.lowerNamedResults(functionCtx, signature),
1663
2512
  }
1664
2513
  if signature.TypeParams() != nil && signature.TypeParams().Len() != 0 {
2514
+ lowered.typeParams = signatureTypeParamNames(signature)
1665
2515
  lowered.params = append(lowered.params, loweredParam{
1666
2516
  name: "__typeArgs",
1667
2517
  typ: "$.GenericTypeArgs | undefined",
@@ -1684,24 +2534,20 @@ func (o *LoweringOwner) lowerFuncDecl(ctx lowerFileContext, decl *ast.FuncDecl)
1684
2534
  lowered.receiverValue = o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(this)"
1685
2535
  }
1686
2536
  }
1687
- if decl.Name.Name == "main" {
1688
- lowered.async = true
1689
- lowered.result = asyncResultType(o.tsSignatureResultFor(ctx.withAsyncFunction(true), signature), true)
1690
- }
1691
2537
  for idx := range signature.Params().Len() {
1692
2538
  param := signature.Params().At(idx)
1693
- lowered.params, lowered.paramBindings = o.appendLoweredParam(ctx, lowered.params, lowered.paramBindings, param, idx, decl.Body == nil || async)
2539
+ lowered.params, lowered.paramBindings = o.appendLoweredParam(functionCtx, lowered.params, lowered.paramBindings, param, idx, decl.Body == nil || async)
1694
2540
  }
1695
2541
  if decl.Body != nil {
1696
- body, diagnostics := o.lowerBlock(ctx.withSignature(signature).withAsyncFunction(async).withDeferState(deferState), decl.Body)
2542
+ body, diagnostics := o.lowerBlock(functionCtx.withAsyncFunction(async).withDeferState(deferState), decl.Body)
1697
2543
  lowered.body = body
1698
2544
  if deferState.async && !lowered.async {
1699
2545
  lowered.async = true
1700
- lowered.result = asyncResultType(o.tsSignatureResultFor(ctx.withAsyncFunction(true), signature), true)
2546
+ lowered.result = asyncResultType(o.tsSignatureResultFor(functionCtx.withAsyncFunction(true), signature), true)
1701
2547
  }
1702
2548
  return lowered, diagnostics
1703
2549
  }
1704
- if zeroReturn, ok := o.lowerBodylessReturnStmt(ctx, signature); ok {
2550
+ if zeroReturn, ok := o.lowerBodylessReturnStmt(functionCtx, signature); ok {
1705
2551
  lowered.body = []loweredStmt{{text: zeroReturn}}
1706
2552
  }
1707
2553
  return lowered, nil
@@ -1754,6 +2600,54 @@ func rangeBindingAssignedInBody(ctx lowerFileContext, expr ast.Expr, body *ast.B
1754
2600
  return objectAssignedInBlock(ctx, obj, body)
1755
2601
  }
1756
2602
 
2603
+ func (o *LoweringOwner) lowerMapRangeBinding(
2604
+ ctx lowerFileContext,
2605
+ expr ast.Expr,
2606
+ name string,
2607
+ fallback string,
2608
+ tempPrefix string,
2609
+ declare bool,
2610
+ ) (string, []loweredStmt, []Diagnostic) {
2611
+ if expr == nil {
2612
+ return fallback, nil, nil
2613
+ }
2614
+ if ident, ok := expr.(*ast.Ident); ok && ident.Name == "_" {
2615
+ return fallback, nil, nil
2616
+ }
2617
+ if declare {
2618
+ obj := rangeBindingObject(ctx, expr)
2619
+ if name == "" || obj == nil || !ctx.model.needsVarRef[obj] {
2620
+ if name != "" {
2621
+ return name, nil, nil
2622
+ }
2623
+ return fallback, nil, nil
2624
+ }
2625
+ rawName := ctx.tempName(tempPrefix)
2626
+ value := rawName
2627
+ if isStructValueType(obj.Type()) {
2628
+ value = o.lowerStructClone(value)
2629
+ }
2630
+ return rawName, []loweredStmt{{
2631
+ text: "let " + name + ": " + o.tsVariableTypeFor(ctx, obj.Type(), true) + " = " +
2632
+ o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(" + value + ")",
2633
+ }}, nil
2634
+ }
2635
+ rawName := ctx.tempName(tempPrefix)
2636
+ left, diagnostics := o.lowerAssignmentTarget(ctx, expr, false)
2637
+ return rawName, []loweredStmt{{text: left + " = " + rawName}}, diagnostics
2638
+ }
2639
+
2640
+ func rangeBindingObject(ctx lowerFileContext, expr ast.Expr) types.Object {
2641
+ ident, ok := expr.(*ast.Ident)
2642
+ if !ok || ident.Name == "_" || ctx.semPkg == nil || ctx.semPkg.source == nil {
2643
+ return nil
2644
+ }
2645
+ if obj := ctx.semPkg.source.TypesInfo.Defs[ident]; obj != nil {
2646
+ return obj
2647
+ }
2648
+ return ctx.semPkg.source.TypesInfo.Uses[ident]
2649
+ }
2650
+
1757
2651
  func expressionUsesObject(ctx lowerFileContext, expr ast.Expr, obj types.Object) bool {
1758
2652
  if expr == nil || obj == nil || ctx.semPkg == nil || ctx.semPkg.source == nil {
1759
2653
  return false
@@ -1803,6 +2697,20 @@ func (o *LoweringOwner) appendLoweredParam(
1803
2697
 
1804
2698
  func (ctx lowerFileContext) withSignature(signature *types.Signature) lowerFileContext {
1805
2699
  ctx.signature = signature
2700
+ if signature != nil && signature.TypeParams() != nil && signature.TypeParams().Len() != 0 {
2701
+ next := make(map[string]bool, len(ctx.typeParams)+signature.TypeParams().Len())
2702
+ maps.Copy(next, ctx.typeParams)
2703
+ nextStatic := make(map[string]bool, len(ctx.staticTypeParams)+signature.TypeParams().Len())
2704
+ maps.Copy(nextStatic, ctx.staticTypeParams)
2705
+ for typeParam := range signature.TypeParams().TypeParams() {
2706
+ next[typeParam.Obj().Name()] = true
2707
+ if signatureUsesTypeParamAsSliceElem(signature, typeParam) {
2708
+ nextStatic[typeParam.Obj().Name()] = true
2709
+ }
2710
+ }
2711
+ ctx.typeParams = next
2712
+ ctx.staticTypeParams = nextStatic
2713
+ }
1806
2714
  return ctx
1807
2715
  }
1808
2716
 
@@ -1852,7 +2760,18 @@ func (ctx lowerFileContext) withoutRangeBreak() lowerFileContext {
1852
2760
  }
1853
2761
 
1854
2762
  func (ctx lowerFileContext) withGotoLabels(labels map[string]bool) lowerFileContext {
1855
- ctx.gotoLabels = labels
2763
+ if len(ctx.gotoLabels) == 0 {
2764
+ ctx.gotoLabels = labels
2765
+ return ctx
2766
+ }
2767
+ merged := make(map[string]bool, len(ctx.gotoLabels)+len(labels))
2768
+ for label := range ctx.gotoLabels {
2769
+ merged[label] = true
2770
+ }
2771
+ for label := range labels {
2772
+ merged[label] = true
2773
+ }
2774
+ ctx.gotoLabels = merged
1856
2775
  return ctx
1857
2776
  }
1858
2777
 
@@ -1884,6 +2803,11 @@ func (ctx lowerFileContext) withLoopLabel(label string) lowerFileContext {
1884
2803
  return ctx
1885
2804
  }
1886
2805
 
2806
+ func (ctx lowerFileContext) withoutLoopLabel() lowerFileContext {
2807
+ ctx.loopLabel = ""
2808
+ return ctx
2809
+ }
2810
+
1887
2811
  func (ctx lowerFileContext) withSwitchBreak() lowerFileContext {
1888
2812
  ctx.switchBreak = true
1889
2813
  return ctx
@@ -1999,6 +2923,22 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
1999
2923
  expr, diagnostics := o.lowerPointerStorageExpr(ctx, star.X)
2000
2924
  return []loweredStmt{{text: expr + typed.Tok.String()}}, diagnostics
2001
2925
  }
2926
+ if index, ok := unwrapParenExpr(typed.X).(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) {
2927
+ right := "1"
2928
+ tok := token.ADD_ASSIGN
2929
+ if typed.Tok == token.DEC {
2930
+ tok = token.SUB_ASSIGN
2931
+ }
2932
+ return o.lowerMapIndexUpdateStmts(ctx, index, tok, right, ctx.semPkg.source.TypesInfo.TypeOf(typed.X))
2933
+ }
2934
+ if setter, ok := o.packageVarSetterForAssignment(ctx, typed.X); ok {
2935
+ expr, diagnostics := o.lowerExpr(ctx, typed.X)
2936
+ op := "+"
2937
+ if typed.Tok == token.DEC {
2938
+ op = "-"
2939
+ }
2940
+ return []loweredStmt{{text: setter + "(" + expr + " " + op + " 1)"}}, diagnostics
2941
+ }
2002
2942
  expr, diagnostics := o.lowerExpr(ctx, typed.X)
2003
2943
  return []loweredStmt{{text: expr + typed.Tok.String()}}, diagnostics
2004
2944
  case *ast.BranchStmt:
@@ -2068,6 +3008,10 @@ func packageVarGetterName(name string) string {
2068
3008
  return "__goscript_get_" + safeIdentifier(name)
2069
3009
  }
2070
3010
 
3011
+ func packageVarInitName(name string) string {
3012
+ return "__goscript_init_" + safeIdentifier(name)
3013
+ }
3014
+
2071
3015
  func (o *LoweringOwner) lowerElse(ctx lowerFileContext, stmt ast.Stmt) ([]loweredStmt, []Diagnostic) {
2072
3016
  switch typed := stmt.(type) {
2073
3017
  case *ast.BlockStmt:
@@ -2190,6 +3134,19 @@ func (o *LoweringOwner) lowerStmtListAfter(
2190
3134
  continue
2191
3135
  }
2192
3136
  }
3137
+ if stmtCtx, nextCtx, ok := o.lowerDeclStatementContext(ctx, stmt); ok {
3138
+ stmtLowered, stmtDiagnostics := o.lowerStmt(stmtCtx, stmt)
3139
+ diagnostics = append(diagnostics, stmtDiagnostics...)
3140
+ if len(stmtLowered) != 0 && len(leading) != 0 {
3141
+ stmtLowered[0].leading = append(leading, stmtLowered[0].leading...)
3142
+ }
3143
+ lowered = append(lowered, stmtLowered...)
3144
+ ctx = nextCtx
3145
+ if endLine := sourceLine(ctx, stmt.End()); endLine != 0 {
3146
+ prevEndLine = endLine
3147
+ }
3148
+ continue
3149
+ }
2193
3150
  if stmtCtx, nextCtx, prelude, ok := o.lowerShortDeclStatementContext(ctx, stmt); ok {
2194
3151
  stmtLowered, stmtDiagnostics := o.lowerStmt(stmtCtx, stmt)
2195
3152
  diagnostics = append(diagnostics, stmtDiagnostics...)
@@ -2221,6 +3178,44 @@ func (o *LoweringOwner) lowerStmtListAfter(
2221
3178
  return lowered, diagnostics
2222
3179
  }
2223
3180
 
3181
+ func (o *LoweringOwner) lowerDeclStatementContext(
3182
+ ctx lowerFileContext,
3183
+ stmt ast.Stmt,
3184
+ ) (lowerFileContext, lowerFileContext, bool) {
3185
+ declStmt, ok := stmt.(*ast.DeclStmt)
3186
+ if !ok {
3187
+ return ctx, ctx, false
3188
+ }
3189
+ genDecl, ok := declStmt.Decl.(*ast.GenDecl)
3190
+ if !ok || genDecl.Tok != token.VAR {
3191
+ return ctx, ctx, false
3192
+ }
3193
+ aliases := make(map[types.Object]string)
3194
+ for _, spec := range genDecl.Specs {
3195
+ valueSpec, ok := spec.(*ast.ValueSpec)
3196
+ if !ok {
3197
+ continue
3198
+ }
3199
+ for _, name := range valueSpec.Names {
3200
+ if name.Name == "_" {
3201
+ continue
3202
+ }
3203
+ def := ctx.semPkg.source.TypesInfo.Defs[name]
3204
+ if def == nil || aliases[def] != "" {
3205
+ continue
3206
+ }
3207
+ if shortDeclDefShadowsOuterName(name.Name, def) {
3208
+ aliases[def] = ctx.tempName("Shadow")
3209
+ }
3210
+ }
3211
+ }
3212
+ if len(aliases) == 0 {
3213
+ return ctx, ctx, false
3214
+ }
3215
+ nextCtx := ctx.withIdentRefAliases(aliases)
3216
+ return nextCtx, nextCtx, true
3217
+ }
3218
+
2224
3219
  type gotoStateCluster struct {
2225
3220
  startIdx int
2226
3221
  firstLabelIdx int
@@ -2387,10 +3382,8 @@ func (o *LoweringOwner) lowerShortDeclStatementContext(
2387
3382
  if len(oldAliases) == 0 && len(newAliases) == 0 {
2388
3383
  return ctx, ctx, nil, false
2389
3384
  }
2390
- stmtAliases := make(map[types.Object]string, len(oldAliases)+len(newAliases))
2391
- maps.Copy(stmtAliases, oldAliases)
2392
- maps.Copy(stmtAliases, newAliases)
2393
- return ctx.withIdentAliases(stmtAliases), ctx.withIdentAliases(newAliases), prelude, true
3385
+ stmtCtx := ctx.withIdentAliases(oldAliases).withIdentRefAliases(newAliases)
3386
+ return stmtCtx, ctx.withIdentRefAliases(newAliases), prelude, true
2394
3387
  }
2395
3388
 
2396
3389
  func (o *LoweringOwner) lowerBackwardGotoLoop(
@@ -2605,6 +3598,9 @@ func (o *LoweringOwner) lowerSendStmt(ctx lowerFileContext, stmt *ast.SendStmt)
2605
3598
  channel, channelDiagnostics := o.lowerExpr(ctx, stmt.Chan)
2606
3599
  value, valueDiagnostics := o.lowerExpr(ctx, stmt.Value)
2607
3600
  diagnostics := append(channelDiagnostics, valueDiagnostics...)
3601
+ if channelType, _ := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(stmt.Chan)).Underlying().(*types.Chan); channelType != nil {
3602
+ value = o.lowerValueForTarget(ctx, stmt.Value, channelType.Elem(), value)
3603
+ }
2608
3604
  return "await " + o.runtimeOwner.QualifiedHelper(RuntimeHelperChanSend) + "(" + channel + ", " + value + ")", diagnostics
2609
3605
  }
2610
3606
 
@@ -2616,6 +3612,25 @@ func (o *LoweringOwner) lowerGoStmt(ctx lowerFileContext, stmt *ast.GoStmt) (str
2616
3612
  }
2617
3613
 
2618
3614
  func (o *LoweringOwner) lowerDeferStmt(ctx lowerFileContext, stmt *ast.DeferStmt) (string, []Diagnostic) {
3615
+ if nestedCall, ok := stmt.Call.Fun.(*ast.CallExpr); ok {
3616
+ callee, diagnostics := o.lowerCallExpr(ctx, nestedCall)
3617
+ args, argDiagnostics := o.lowerCallArgs(ctx, stmt.Call, callTargetSignature(ctx, stmt.Call.Fun))
3618
+ diagnostics = append(diagnostics, argDiagnostics...)
3619
+ calleeTemp := ctx.tempName("DeferCallee")
3620
+ call := o.lowerCallableExpr(ctx, stmt.Call.Fun, calleeTemp) + "(" + strings.Join(args, ", ") + ")"
3621
+ call = o.awaitCallIfNeeded(ctx, stmt.Call.Fun, call)
3622
+ async := strings.Contains(callee, "await ") || strings.Contains(call, "await ")
3623
+ if ctx.deferState != nil {
3624
+ ctx.deferState.used = true
3625
+ if async {
3626
+ ctx.deferState.async = true
3627
+ }
3628
+ }
3629
+ if async {
3630
+ return "const " + calleeTemp + " = " + callee + "\n__defer.defer(async () => { " + call + " })", diagnostics
3631
+ }
3632
+ return "const " + calleeTemp + " = " + callee + "\n__defer.defer(() => { " + call + " })", diagnostics
3633
+ }
2619
3634
  call, diagnostics := o.lowerCallExpr(ctx, stmt.Call)
2620
3635
  async := strings.Contains(call, "await ")
2621
3636
  if ctx.deferState != nil {
@@ -2682,41 +3697,51 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
2682
3697
  isShortDecl := stmt.Tok == token.DEFINE && isShortAssignTargetNew(ctx, lhs)
2683
3698
  right, rightDiagnostics := o.lowerExpr(ctx, stmt.Rhs[idx])
2684
3699
  diagnostics = append(diagnostics, rightDiagnostics...)
2685
- targetType := ctx.semPkg.source.TypesInfo.TypeOf(lhs)
3700
+ targetType := assignmentTargetType(ctx, lhs)
2686
3701
  right = o.lowerValueForTarget(ctx, stmt.Rhs[idx], targetType, right)
2687
- if setter, ok := o.packageVarSetterForAssignment(ctx, lhs); ok && stmt.Tok == token.ASSIGN {
2688
- stmts = append(stmts, loweredStmt{text: setter + "(" + right + ")"})
3702
+ if targetType != nil && genericCallResultUsesTypeParam(ctx, stmt.Rhs[idx]) {
3703
+ right = "(" + right + " as " + o.tsTypeFor(ctx, targetType) + ")"
3704
+ }
3705
+ if setter, ok := o.packageVarSetterForAssignment(ctx, lhs); ok {
3706
+ value, ok := o.packageVarAssignmentValue(ctx, lhs, targetType, right, stmt.Tok)
3707
+ if !ok {
3708
+ value = right
3709
+ }
3710
+ stmts = append(stmts, loweredStmt{text: setter + "(" + value + ")"})
2689
3711
  continue
2690
3712
  }
2691
- left, leftDiagnostics := o.lowerAssignmentTarget(ctx, lhs, isShortDecl)
2692
- diagnostics = append(diagnostics, leftDiagnostics...)
2693
- if index, ok := lhs.(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) && stmt.Tok == token.ASSIGN {
2694
- mapExpr, mapDiagnostics := o.lowerExpr(ctx, index.X)
2695
- keyExpr, keyDiagnostics := o.lowerExpr(ctx, index.Index)
2696
- diagnostics = append(diagnostics, mapDiagnostics...)
2697
- diagnostics = append(diagnostics, keyDiagnostics...)
2698
- stmts = append(stmts, loweredStmt{text: o.runtimeOwner.QualifiedHelper(RuntimeHelperMapSet) + "(" + mapExpr + ", " + keyExpr + ", " + right + ")"})
3713
+ if index, ok := lhs.(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) && stmt.Tok != token.DEFINE {
3714
+ update, updateDiagnostics := o.lowerMapIndexUpdateStmts(ctx, index, stmt.Tok, right, targetType)
3715
+ diagnostics = append(diagnostics, updateDiagnostics...)
3716
+ stmts = append(stmts, update...)
2699
3717
  continue
2700
3718
  }
2701
- if star, ok := lhs.(*ast.StarExpr); ok && stmt.Tok == token.ASSIGN && isStructValueType(targetType) {
3719
+ left, leftDiagnostics := o.lowerAssignmentTarget(ctx, lhs, isShortDecl)
3720
+ diagnostics = append(diagnostics, leftDiagnostics...)
3721
+ star, starTarget := unwrapParenExpr(lhs).(*ast.StarExpr)
3722
+ if starTarget && stmt.Tok == token.ASSIGN && isStructValueType(targetType) {
2702
3723
  pointer, pointerDiagnostics := o.lowerPointerValueExpr(ctx, star.X)
2703
3724
  diagnostics = append(diagnostics, pointerDiagnostics...)
2704
3725
  stmts = append(stmts, loweredStmt{text: o.runtimeOwner.QualifiedHelper(RuntimeHelperAssignStruct) + "(" + pointer + ", " + right + ")"})
2705
3726
  continue
2706
3727
  }
2707
- if star, ok := lhs.(*ast.StarExpr); ok && stmt.Tok == token.ASSIGN {
3728
+ if starTarget && stmt.Tok == token.ASSIGN {
2708
3729
  pointer, pointerDiagnostics := o.lowerPointerStorageExpr(ctx, star.X)
2709
3730
  diagnostics = append(diagnostics, pointerDiagnostics...)
2710
3731
  stmts = append(stmts, loweredStmt{text: pointer + " = " + right})
2711
3732
  continue
2712
3733
  }
2713
- if star, ok := lhs.(*ast.StarExpr); ok && stmt.Tok != token.DEFINE {
3734
+ if starTarget && stmt.Tok != token.DEFINE {
2714
3735
  pointer, pointerDiagnostics := o.lowerPointerStorageExpr(ctx, star.X)
2715
3736
  diagnostics = append(diagnostics, pointerDiagnostics...)
2716
3737
  if stmt.Tok == token.AND_NOT_ASSIGN {
2717
3738
  stmts = append(stmts, loweredStmt{text: pointer + " = " + pointer + " & ~(" + right + ")"})
2718
3739
  continue
2719
3740
  }
3741
+ if value, ok := integerQuotientAssignExpr(targetType, pointer, right, stmt.Tok); ok {
3742
+ stmts = append(stmts, loweredStmt{text: value})
3743
+ continue
3744
+ }
2720
3745
  stmts = append(stmts, loweredStmt{text: pointer + " " + stmt.Tok.String() + " " + right})
2721
3746
  continue
2722
3747
  }
@@ -2735,13 +3760,109 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
2735
3760
  stmts = append(stmts, loweredStmt{text: left + " = " + o.runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")"})
2736
3761
  continue
2737
3762
  }
3763
+ if value, ok := integerQuotientAssignExpr(targetType, left, right, stmt.Tok); ok {
3764
+ stmts = append(stmts, loweredStmt{text: value})
3765
+ continue
3766
+ }
2738
3767
  op := stmt.Tok.String()
2739
3768
  if stmt.Tok == token.DEFINE {
2740
3769
  op = "="
2741
3770
  }
2742
- stmts = append(stmts, loweredStmt{text: left + " " + op + " " + right})
3771
+ stmts = append(stmts, loweredStmt{text: left + " " + op + " " + right})
3772
+ }
3773
+ return stmts, diagnostics
3774
+ }
3775
+
3776
+ func (o *LoweringOwner) lowerMapIndexUpdateStmts(
3777
+ ctx lowerFileContext,
3778
+ index *ast.IndexExpr,
3779
+ tok token.Token,
3780
+ right string,
3781
+ targetType types.Type,
3782
+ ) ([]loweredStmt, []Diagnostic) {
3783
+ mapExpr, mapDiagnostics := o.lowerExpr(ctx, index.X)
3784
+ keyExpr, keyDiagnostics := o.lowerExpr(ctx, index.Index)
3785
+ diagnostics := append(mapDiagnostics, keyDiagnostics...)
3786
+ if tok == token.ASSIGN {
3787
+ return []loweredStmt{{text: o.runtimeOwner.QualifiedHelper(RuntimeHelperMapSet) + "(" + mapExpr + ", " + keyExpr + ", " + right + ")"}}, diagnostics
3788
+ }
3789
+ mapTemp := ctx.tempName("Map")
3790
+ keyTemp := ctx.tempName("MapKey")
3791
+ current := o.lowerMapGetValue(ctx, index, mapTemp, keyTemp)
3792
+ value := lowerCompoundAssignValue(o.runtimeOwner, targetType, current, right, tok)
3793
+ return []loweredStmt{
3794
+ {text: "const " + mapTemp + " = " + mapExpr},
3795
+ {text: "const " + keyTemp + " = " + keyExpr},
3796
+ {text: o.runtimeOwner.QualifiedHelper(RuntimeHelperMapSet) + "(" + mapTemp + ", " + keyTemp + ", " + value + ")"},
3797
+ }, diagnostics
3798
+ }
3799
+
3800
+ func lowerCompoundAssignValue(
3801
+ runtimeOwner *RuntimeContractOwner,
3802
+ targetType types.Type,
3803
+ left string,
3804
+ right string,
3805
+ tok token.Token,
3806
+ ) string {
3807
+ if helper, ok := wideIntegerAssignHelper(targetType, tok); ok {
3808
+ return runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")"
3809
+ }
3810
+ if value, ok := integerQuotientAssignValueExpr(targetType, left, right, tok); ok {
3811
+ return value
3812
+ }
3813
+ switch tok {
3814
+ case token.ADD_ASSIGN:
3815
+ return left + " + " + right
3816
+ case token.SUB_ASSIGN:
3817
+ return left + " - " + right
3818
+ case token.MUL_ASSIGN:
3819
+ return left + " * " + right
3820
+ case token.QUO_ASSIGN:
3821
+ return left + " / " + right
3822
+ case token.REM_ASSIGN:
3823
+ return left + " % " + right
3824
+ case token.AND_ASSIGN:
3825
+ return left + " & " + right
3826
+ case token.OR_ASSIGN:
3827
+ return left + " | " + right
3828
+ case token.XOR_ASSIGN:
3829
+ return left + " ^ " + right
3830
+ case token.SHL_ASSIGN:
3831
+ return left + " << " + right
3832
+ case token.SHR_ASSIGN:
3833
+ return left + " >> " + right
3834
+ case token.AND_NOT_ASSIGN:
3835
+ return left + " & ~(" + right + ")"
3836
+ default:
3837
+ return right
3838
+ }
3839
+ }
3840
+
3841
+ func integerQuotientAssignExpr(targetType types.Type, left string, right string, tok token.Token) (string, bool) {
3842
+ value, ok := integerQuotientAssignValueExpr(targetType, left, right, tok)
3843
+ if !ok {
3844
+ return "", false
3845
+ }
3846
+ return left + " = " + value, true
3847
+ }
3848
+
3849
+ func assignmentTargetType(ctx lowerFileContext, lhs ast.Expr) types.Type {
3850
+ if ident, ok := lhs.(*ast.Ident); ok {
3851
+ if obj := ctx.semPkg.source.TypesInfo.Defs[ident]; obj != nil {
3852
+ return obj.Type()
3853
+ }
2743
3854
  }
2744
- return stmts, diagnostics
3855
+ return ctx.semPkg.source.TypesInfo.TypeOf(lhs)
3856
+ }
3857
+
3858
+ func integerQuotientAssignValueExpr(targetType types.Type, left string, right string, tok token.Token) (string, bool) {
3859
+ if tok != token.QUO_ASSIGN || !isIntegerType(targetType) {
3860
+ return "", false
3861
+ }
3862
+ if bits, ok := unsignedIntegerBits(targetType); ok && bits <= 32 {
3863
+ return "(" + left + " / " + right + ") >>> 0", true
3864
+ }
3865
+ return "Math.trunc(" + left + " / " + right + ")", true
2745
3866
  }
2746
3867
 
2747
3868
  func wideIntegerAssignHelper(targetType types.Type, tok token.Token) (RuntimeHelper, bool) {
@@ -2754,17 +3875,21 @@ func wideIntegerAssignHelper(targetType types.Type, tok token.Token) (RuntimeHel
2754
3875
  case token.SHR_ASSIGN:
2755
3876
  return RuntimeHelperUint64Shr, true
2756
3877
  case token.MUL_ASSIGN:
2757
- return RuntimeHelperUint64Mul, true
3878
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Mul, RuntimeHelperInt64Mul), true
3879
+ case token.QUO_ASSIGN:
3880
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Div, RuntimeHelperInt64Div), true
3881
+ case token.REM_ASSIGN:
3882
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Mod, RuntimeHelperInt64Mod), true
2758
3883
  case token.ADD_ASSIGN:
2759
- return RuntimeHelperUint64Add, true
3884
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Add, RuntimeHelperInt64Add), true
2760
3885
  case token.SUB_ASSIGN:
2761
- return RuntimeHelperUint64Sub, true
3886
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Sub, RuntimeHelperInt64Sub), true
2762
3887
  case token.AND_ASSIGN:
2763
- return RuntimeHelperUint64And, true
3888
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64And, RuntimeHelperInt64And), true
2764
3889
  case token.OR_ASSIGN:
2765
- return RuntimeHelperUint64Or, true
3890
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Or, RuntimeHelperInt64Or), true
2766
3891
  case token.XOR_ASSIGN:
2767
- return RuntimeHelperUint64Xor, true
3892
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Xor, RuntimeHelperInt64Xor), true
2768
3893
  default:
2769
3894
  return "", false
2770
3895
  }
@@ -2834,14 +3959,15 @@ func (o *LoweringOwner) shortDeclTypeAnnotation(ctx lowerFileContext, lhs ast.Ex
2834
3959
  if obj == nil {
2835
3960
  return ""
2836
3961
  }
2837
- if signature := unnamedSignatureForType(obj.Type()); signature != nil && rhsIsMethodValue(ctx, rhs) {
2838
- return ": " + o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
2839
- }
2840
3962
  if signature := unnamedSignatureForType(obj.Type()); signature != nil {
2841
- value := ctx.model.values[obj]
2842
- if value != nil && value.asyncCompatibleFunction {
2843
- return ": " + o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
3963
+ typ := o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
3964
+ if ctx.model.needsVarRef[obj] {
3965
+ typ = "$.VarRef<" + typ + ">"
2844
3966
  }
3967
+ return ": " + typ
3968
+ }
3969
+ if rhs != nil && isIdentLikeExpr(rhs) && isInterfaceType(obj.Type()) {
3970
+ return ": " + o.tsVariableTypeFor(ctx, obj.Type(), ctx.model.needsVarRef[obj])
2845
3971
  }
2846
3972
  if !shortDeclNeedsTypeAnnotation(obj.Type()) {
2847
3973
  return ""
@@ -2849,12 +3975,19 @@ func (o *LoweringOwner) shortDeclTypeAnnotation(ctx lowerFileContext, lhs ast.Ex
2849
3975
  return ": " + o.tsVariableTypeFor(ctx, obj.Type(), ctx.model.needsVarRef[obj])
2850
3976
  }
2851
3977
 
3978
+ func isIdentLikeExpr(expr ast.Expr) bool {
3979
+ _, ok := ast.Unparen(expr).(*ast.Ident)
3980
+ return ok
3981
+ }
3982
+
2852
3983
  func shortDeclNeedsTypeAnnotation(typ types.Type) bool {
2853
3984
  switch typed := types.Unalias(typ).Underlying().(type) {
2854
3985
  case *types.Pointer:
2855
- return namedStructType(typed.Elem()) != nil
3986
+ return namedStructType(typed.Elem()) != nil || namedNonStructType(typed.Elem()) != nil
2856
3987
  case *types.Map:
2857
3988
  return true
3989
+ case *types.Slice:
3990
+ return true
2858
3991
  default:
2859
3992
  return false
2860
3993
  }
@@ -2876,6 +4009,15 @@ func (o *LoweringOwner) lowerTupleTargetAssignmentStmt(
2876
4009
  declare bool,
2877
4010
  ) (loweredStmt, []Diagnostic) {
2878
4011
  if !declare {
4012
+ if index, ok := unwrapParenExpr(lhs).(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) {
4013
+ targetType := assignmentTargetType(ctx, lhs)
4014
+ value = o.lowerValueForTarget(ctx, lhs, targetType, value)
4015
+ stmts, diagnostics := o.lowerMapIndexUpdateStmts(ctx, index, token.ASSIGN, value, targetType)
4016
+ if len(stmts) != 0 {
4017
+ return stmts[0], diagnostics
4018
+ }
4019
+ return loweredStmt{}, diagnostics
4020
+ }
2879
4021
  if stmt, diagnostics, ok := o.lowerStarTargetAssignmentStmt(ctx, lhs, value); ok {
2880
4022
  return stmt, diagnostics
2881
4023
  }
@@ -2895,7 +4037,7 @@ func (o *LoweringOwner) lowerStarTargetAssignmentStmt(
2895
4037
  lhs ast.Expr,
2896
4038
  right string,
2897
4039
  ) (loweredStmt, []Diagnostic, bool) {
2898
- star, ok := lhs.(*ast.StarExpr)
4040
+ star, ok := unwrapParenExpr(lhs).(*ast.StarExpr)
2899
4041
  if !ok {
2900
4042
  return loweredStmt{}, nil, false
2901
4043
  }
@@ -2915,7 +4057,7 @@ func (o *LoweringOwner) lowerTupleReassignmentStmt(
2915
4057
  diagnostics []Diagnostic,
2916
4058
  ) ([]loweredStmt, []Diagnostic) {
2917
4059
  tempName := ctx.tempName("Tuple")
2918
- stmts := []loweredStmt{{text: "let " + tempName + " = " + right}}
4060
+ stmts := []loweredStmt{{text: "let " + tempName + ": any = " + right}}
2919
4061
  for idx, lhs := range stmt.Lhs {
2920
4062
  if ident, ok := lhs.(*ast.Ident); ok && ident.Name == "_" {
2921
4063
  continue
@@ -3064,8 +4206,8 @@ func shortDeclDefShadowsOuterName(name string, def types.Object) bool {
3064
4206
  if scope == def.Parent() {
3065
4207
  continue
3066
4208
  }
3067
- obj, ok := scope.Lookup(name).(*types.Var)
3068
- if ok && obj.Pos().IsValid() && obj.Pos() < def.Pos() {
4209
+ obj := scope.Lookup(name)
4210
+ if obj != nil && obj.Pos().IsValid() && obj.Pos() < def.Pos() {
3069
4211
  return true
3070
4212
  }
3071
4213
  }
@@ -3281,6 +4423,9 @@ func (o *LoweringOwner) lowerReturnStmt(ctx lowerFileContext, stmt *ast.ReturnSt
3281
4423
  if ctx.rangeBranch != nil {
3282
4424
  return o.lowerRangeFuncReturnStmt(ctx, stmt)
3283
4425
  }
4426
+ if o.returnNeedsNamedResultDefer(ctx) {
4427
+ return o.lowerNamedResultDeferReturnStmt(ctx, stmt)
4428
+ }
3284
4429
  if len(stmt.Results) == 0 {
3285
4430
  if result, ok := o.lowerNamedResultReturn(ctx); ok {
3286
4431
  return "return " + result, nil
@@ -3313,6 +4458,125 @@ func (o *LoweringOwner) lowerReturnStmt(ctx lowerFileContext, stmt *ast.ReturnSt
3313
4458
  return "return [" + strings.Join(parts, ", ") + "]", diagnostics
3314
4459
  }
3315
4460
 
4461
+ func (o *LoweringOwner) returnNeedsNamedResultDefer(ctx lowerFileContext) bool {
4462
+ if ctx.deferState == nil || !ctx.deferState.used || ctx.signature == nil || ctx.signature.Results() == nil {
4463
+ return false
4464
+ }
4465
+ for result := range ctx.signature.Results().Variables() {
4466
+ if result.Name() != "" {
4467
+ return true
4468
+ }
4469
+ }
4470
+ return false
4471
+ }
4472
+
4473
+ func (o *LoweringOwner) lowerNamedResultDeferReturnStmt(ctx lowerFileContext, stmt *ast.ReturnStmt) (string, []Diagnostic) {
4474
+ var diagnostics []Diagnostic
4475
+ var lines []string
4476
+ explicitTemp := ""
4477
+ if len(stmt.Results) != 0 {
4478
+ var value string
4479
+ var values []string
4480
+ if len(stmt.Results) == 1 && ctx.signature.Results().Len() > 1 {
4481
+ expr, exprDiagnostics := o.lowerExpr(ctx, stmt.Results[0])
4482
+ diagnostics = append(diagnostics, exprDiagnostics...)
4483
+ if prefix, tuple, ok := o.lowerTupleReturnValue(ctx, stmt.Results[0], expr); ok {
4484
+ lines = append(lines, prefix)
4485
+ value = tuple
4486
+ } else {
4487
+ value = expr
4488
+ }
4489
+ } else {
4490
+ values = make([]string, 0, len(stmt.Results))
4491
+ for idx, result := range stmt.Results {
4492
+ expr, exprDiagnostics := o.lowerExpr(ctx, result)
4493
+ diagnostics = append(diagnostics, exprDiagnostics...)
4494
+ if idx < ctx.signature.Results().Len() {
4495
+ expr = o.lowerValueForTarget(ctx, result, ctx.signature.Results().At(idx).Type(), expr)
4496
+ }
4497
+ values = append(values, expr)
4498
+ }
4499
+ }
4500
+ temp := ctx.tempName("Return")
4501
+ explicitTemp = temp
4502
+ tempType := o.tsSignatureResultFor(ctx, ctx.signature)
4503
+ if value != "" {
4504
+ lines = append(lines, "const "+temp+": "+tempType+" = "+value)
4505
+ } else if len(values) == 1 {
4506
+ lines = append(lines, "const "+temp+": "+tempType+" = "+values[0])
4507
+ } else {
4508
+ lines = append(lines, "const "+temp+": "+tempType+" = ["+strings.Join(values, ", ")+"]")
4509
+ }
4510
+ for idx := range ctx.signature.Results().Len() {
4511
+ result := ctx.signature.Results().At(idx)
4512
+ name := result.Name()
4513
+ if name == "" || name == "_" {
4514
+ continue
4515
+ }
4516
+ target := safeIdentifier(name)
4517
+ if ctx.model.needsVarRef[result] {
4518
+ target += ".value"
4519
+ }
4520
+ source := temp
4521
+ if ctx.signature.Results().Len() > 1 {
4522
+ source += "[" + strconv.Itoa(idx) + "]"
4523
+ }
4524
+ lines = append(lines, target+" = "+source)
4525
+ }
4526
+ }
4527
+ lines = append(lines, o.lowerDeferDisposeStmt(ctx))
4528
+ if result, ok := o.lowerNamedResultReturnWithExplicitTemp(ctx, explicitTemp); ok {
4529
+ lines = append(lines, "return "+result)
4530
+ } else {
4531
+ lines = append(lines, "return")
4532
+ }
4533
+ return strings.Join(lines, "\n"), diagnostics
4534
+ }
4535
+
4536
+ func (o *LoweringOwner) lowerNamedResultReturnWithExplicitTemp(ctx lowerFileContext, explicitTemp string) (string, bool) {
4537
+ if explicitTemp == "" {
4538
+ return o.lowerNamedResultReturn(ctx)
4539
+ }
4540
+ parts := make([]string, 0, ctx.signature.Results().Len())
4541
+ hasNamedResult := false
4542
+ multi := ctx.signature.Results().Len() > 1
4543
+ for idx := range ctx.signature.Results().Len() {
4544
+ result := ctx.signature.Results().At(idx)
4545
+ name := result.Name()
4546
+ if name == "" || name == "_" {
4547
+ source := explicitTemp
4548
+ if multi {
4549
+ source += "[" + strconv.Itoa(idx) + "]"
4550
+ }
4551
+ parts = append(parts, source)
4552
+ if name != "" {
4553
+ hasNamedResult = true
4554
+ }
4555
+ continue
4556
+ }
4557
+ hasNamedResult = true
4558
+ returnExpr := safeIdentifier(name)
4559
+ if ctx.model.needsVarRef[result] {
4560
+ returnExpr += ".value"
4561
+ }
4562
+ parts = append(parts, returnExpr)
4563
+ }
4564
+ if !hasNamedResult {
4565
+ return "", false
4566
+ }
4567
+ if len(parts) == 1 {
4568
+ return parts[0], true
4569
+ }
4570
+ return "[" + strings.Join(parts, ", ") + "]", true
4571
+ }
4572
+
4573
+ func (o *LoweringOwner) lowerDeferDisposeStmt(ctx lowerFileContext) string {
4574
+ if ctx.deferState != nil && ctx.deferState.async {
4575
+ return "await __defer[Symbol.asyncDispose]()"
4576
+ }
4577
+ return "__defer[Symbol.dispose]()"
4578
+ }
4579
+
3316
4580
  func (o *LoweringOwner) lowerBodylessReturnStmt(ctx lowerFileContext, signature *types.Signature) (string, bool) {
3317
4581
  if signature.Results().Len() == 0 {
3318
4582
  return "", false
@@ -3434,6 +4698,9 @@ func genericCallResultUsesTypeParam(ctx lowerFileContext, expr ast.Expr) bool {
3434
4698
  return false
3435
4699
  }
3436
4700
  signature := genericFunctionSignatureForCall(ctx, call.Fun)
4701
+ if signature == nil {
4702
+ signature = sourceFunctionSignatureForCall(ctx, call.Fun)
4703
+ }
3437
4704
  if signature == nil || signature.Results() == nil || signature.Results().Len() != 1 {
3438
4705
  return false
3439
4706
  }
@@ -3446,6 +4713,9 @@ func genericCallTupleResultTypeParamIndexes(ctx lowerFileContext, expr ast.Expr)
3446
4713
  return nil
3447
4714
  }
3448
4715
  signature := genericFunctionSignatureForCall(ctx, call.Fun)
4716
+ if signature == nil {
4717
+ signature = sourceFunctionSignatureForCall(ctx, call.Fun)
4718
+ }
3449
4719
  if signature == nil || signature.Results() == nil || signature.Results().Len() < 2 {
3450
4720
  return nil
3451
4721
  }
@@ -3471,6 +4741,30 @@ func genericFunctionSignatureForCall(ctx lowerFileContext, fun ast.Expr) *types.
3471
4741
  }
3472
4742
  }
3473
4743
 
4744
+ func sourceFunctionSignatureForCall(ctx lowerFileContext, fun ast.Expr) *types.Signature {
4745
+ for {
4746
+ switch typed := ast.Unparen(fun).(type) {
4747
+ case *ast.IndexExpr:
4748
+ fun = typed.X
4749
+ case *ast.IndexListExpr:
4750
+ fun = typed.X
4751
+ default:
4752
+ if ctx.semPkg == nil || ctx.semPkg.source == nil {
4753
+ return nil
4754
+ }
4755
+ fn := calledFunction(ctx.semPkg.source, fun)
4756
+ if fn == nil {
4757
+ return nil
4758
+ }
4759
+ if origin := fn.Origin(); origin != nil {
4760
+ fn = origin
4761
+ }
4762
+ signature, _ := fn.Type().(*types.Signature)
4763
+ return signature
4764
+ }
4765
+ }
4766
+ }
4767
+
3474
4768
  func typeContainsTypeParam(typ types.Type) bool {
3475
4769
  return typeContainsTypeParamSeen(typ, make(map[types.Type]bool))
3476
4770
  }
@@ -3569,27 +4863,57 @@ func (o *LoweringOwner) lowerNamedResults(ctx lowerFileContext, signature *types
3569
4863
  }
3570
4864
 
3571
4865
  func (o *LoweringOwner) lowerNamedResultReturn(ctx lowerFileContext) (string, bool) {
3572
- results := o.lowerNamedResults(ctx, ctx.signature)
3573
- if len(results) == 0 {
4866
+ if ctx.signature == nil || ctx.signature.Results() == nil || ctx.signature.Results().Len() == 0 {
3574
4867
  return "", false
3575
4868
  }
3576
- if len(results) == 1 {
3577
- return results[0].returnExpr, true
4869
+ parts := make([]string, 0, ctx.signature.Results().Len())
4870
+ hasNamedResult := false
4871
+ for result := range ctx.signature.Results().Variables() {
4872
+ name := result.Name()
4873
+ if name == "" {
4874
+ parts = append(parts, o.lowerDeclarationZeroValueExpr(ctx, result.Type()))
4875
+ continue
4876
+ }
4877
+ hasNamedResult = true
4878
+ if name == "_" {
4879
+ parts = append(parts, o.lowerDeclarationZeroValueExpr(ctx, result.Type()))
4880
+ continue
4881
+ }
4882
+ returnExpr := safeIdentifier(name)
4883
+ if ctx.model.needsVarRef[result] {
4884
+ returnExpr += ".value"
4885
+ }
4886
+ parts = append(parts, returnExpr)
4887
+ }
4888
+ if !hasNamedResult {
4889
+ return "", false
3578
4890
  }
3579
- parts := make([]string, 0, len(results))
3580
- for _, result := range results {
3581
- parts = append(parts, result.returnExpr)
4891
+ if len(parts) == 1 {
4892
+ return parts[0], true
3582
4893
  }
3583
4894
  return "[" + strings.Join(parts, ", ") + "]", true
3584
4895
  }
3585
4896
 
3586
4897
  func (o *LoweringOwner) lowerForStmt(ctx lowerFileContext, stmt *ast.ForStmt) (loweredStmt, []Diagnostic) {
3587
- bodyCtx := ctx.withoutRangeLoopBranches()
4898
+ bodyCtx := ctx.withoutRangeLoopBranches().withoutLoopLabel()
3588
4899
  loopLabel := ""
3589
4900
  if stmtListNeedsLoopBranchLabel(stmt.Body.List) {
3590
4901
  loopLabel = ctx.tempName("Loop")
3591
4902
  bodyCtx = bodyCtx.withLoopLabel(loopLabel)
3592
4903
  }
4904
+ initCtx := ctx
4905
+ loopCtx := ctx
4906
+ var initPrelude []loweredStmt
4907
+ if assign, ok := stmt.Init.(*ast.AssignStmt); ok && assign.Tok == token.DEFINE {
4908
+ oldAliases, prelude := o.lowerShortDeclShadowAliases(ctx, assign)
4909
+ newAliases := o.lowerShortDeclNewShadowAliases(ctx, assign)
4910
+ if len(oldAliases) != 0 || len(newAliases) != 0 {
4911
+ initCtx = ctx.withIdentAliases(oldAliases).withIdentRefAliases(newAliases)
4912
+ loopCtx = ctx.withIdentRefAliases(newAliases)
4913
+ bodyCtx = bodyCtx.withIdentRefAliases(newAliases)
4914
+ initPrelude = prelude
4915
+ }
4916
+ }
3593
4917
  if stmt.Init == nil && stmt.Post == nil {
3594
4918
  cond := "true"
3595
4919
  var diagnostics []Diagnostic
@@ -3614,19 +4938,19 @@ func (o *LoweringOwner) lowerForStmt(ctx lowerFileContext, stmt *ast.ForStmt) (l
3614
4938
  init := ""
3615
4939
  var diagnostics []Diagnostic
3616
4940
  if stmt.Init != nil {
3617
- lowered, initDiagnostics := o.lowerForInitStmt(ctx, stmt.Init)
4941
+ lowered, initDiagnostics := o.lowerForInitStmt(initCtx, stmt.Init)
3618
4942
  diagnostics = append(diagnostics, initDiagnostics...)
3619
4943
  init = lowered
3620
4944
  }
3621
4945
  cond := ""
3622
4946
  if stmt.Cond != nil {
3623
4947
  var condDiagnostics []Diagnostic
3624
- cond, condDiagnostics = o.lowerExpr(ctx, stmt.Cond)
4948
+ cond, condDiagnostics = o.lowerExpr(loopCtx, stmt.Cond)
3625
4949
  diagnostics = append(diagnostics, condDiagnostics...)
3626
4950
  }
3627
4951
  post := ""
3628
4952
  if stmt.Post != nil {
3629
- lowered, postDiagnostics := o.lowerForPostStmt(ctx, stmt.Post)
4953
+ lowered, postDiagnostics := o.lowerForPostStmt(loopCtx, stmt.Post)
3630
4954
  diagnostics = append(diagnostics, postDiagnostics...)
3631
4955
  post = lowered
3632
4956
  }
@@ -3636,11 +4960,15 @@ func (o *LoweringOwner) lowerForStmt(ctx lowerFileContext, stmt *ast.ForStmt) (l
3636
4960
  if loopLabel != "" {
3637
4961
  text = loopLabel + ": " + text
3638
4962
  }
3639
- return loweredStmt{
4963
+ forStmt := loweredStmt{
3640
4964
  hasBlock: true,
3641
4965
  text: text,
3642
4966
  children: body,
3643
- }, diagnostics
4967
+ }
4968
+ if len(initPrelude) != 0 {
4969
+ return loweredStmt{children: append(initPrelude, forStmt)}, diagnostics
4970
+ }
4971
+ return forStmt, diagnostics
3644
4972
  }
3645
4973
 
3646
4974
  func (o *LoweringOwner) lowerForInitStmt(ctx lowerFileContext, stmt ast.Stmt) (string, []Diagnostic) {
@@ -3729,9 +5057,13 @@ func (o *LoweringOwner) lowerForPostStmt(ctx lowerFileContext, stmt ast.Stmt) (s
3729
5057
  diagnostics = append(diagnostics, leftDiagnostics...)
3730
5058
  lefts = append(lefts, left)
3731
5059
  }
3732
- for _, rhs := range assign.Rhs {
5060
+ for idx, rhs := range assign.Rhs {
3733
5061
  right, rightDiagnostics := o.lowerExpr(ctx, rhs)
3734
5062
  diagnostics = append(diagnostics, rightDiagnostics...)
5063
+ if idx < len(assign.Lhs) {
5064
+ targetType := ctx.semPkg.source.TypesInfo.TypeOf(assign.Lhs[idx])
5065
+ right = o.lowerValueForTarget(ctx, rhs, targetType, right)
5066
+ }
3735
5067
  rights = append(rights, right)
3736
5068
  }
3737
5069
  return "[" + strings.Join(lefts, ", ") + "] = [" + strings.Join(rights, ", ") + "]", diagnostics
@@ -3746,7 +5078,7 @@ func (o *LoweringOwner) lowerForPostStmt(ctx lowerFileContext, stmt ast.Stmt) (s
3746
5078
  func (o *LoweringOwner) lowerRangeStmt(ctx lowerFileContext, stmt *ast.RangeStmt) (loweredStmt, []Diagnostic) {
3747
5079
  rangeValue, diagnostics := o.lowerExpr(ctx, stmt.X)
3748
5080
  aliases := o.lowerRangeDeclShadowAliases(ctx, stmt)
3749
- bodyCtx := ctx
5081
+ bodyCtx := ctx.withoutLoopLabel()
3750
5082
  if len(aliases) != 0 {
3751
5083
  bodyCtx = bodyCtx.withIdentAliases(aliases)
3752
5084
  }
@@ -3795,23 +5127,21 @@ func (o *LoweringOwner) lowerRangeStmt(ctx lowerFileContext, stmt *ast.RangeStmt
3795
5127
  if strings.HasPrefix(rangeTarget, "await ") {
3796
5128
  rangeTarget = "(" + rangeTarget + ")"
3797
5129
  }
3798
- key := keyName
3799
- if key == "" {
3800
- key = "__rangeKey"
3801
- }
3802
- value := valueName
3803
- if value == "" {
3804
- value = "__rangeValue"
3805
- }
5130
+ key, keyBindings, keyDiagnostics := o.lowerMapRangeBinding(ctx, stmt.Key, keyName, "__rangeKey", "RangeKey", stmt.Tok == token.DEFINE)
5131
+ value, valueBindings, valueDiagnostics := o.lowerMapRangeBinding(ctx, stmt.Value, valueName, "__rangeValue", "RangeValue", stmt.Tok == token.DEFINE)
5132
+ diagnostics = append(diagnostics, keyDiagnostics...)
5133
+ diagnostics = append(diagnostics, valueDiagnostics...)
3806
5134
  binding := "const"
3807
5135
  if rangeBindingAssignedInBody(ctx, stmt.Key, stmt.Body) ||
3808
5136
  rangeBindingAssignedInBody(ctx, stmt.Value, stmt.Body) {
3809
5137
  binding = "let"
3810
5138
  }
5139
+ children := append(keyBindings, valueBindings...)
5140
+ children = append(children, body...)
3811
5141
  return loweredStmt{
3812
5142
  hasBlock: true,
3813
5143
  text: "for (" + binding + " [" + key + ", " + value + "] of " + rangeTarget + "?.entries() ?? [])",
3814
- children: body,
5144
+ children: children,
3815
5145
  }, diagnostics
3816
5146
  }
3817
5147
  if isStringType(rangeType) {
@@ -3848,8 +5178,12 @@ func (o *LoweringOwner) lowerRangeStmt(ctx lowerFileContext, stmt *ast.RangeStmt
3848
5178
 
3849
5179
  body, bodyDiagnostics := o.lowerBlock(bodyCtx.withoutRangeLoopBranches(), stmt.Body)
3850
5180
  diagnostics = append(diagnostics, bodyDiagnostics...)
3851
- rangeTarget := o.lowerArrayPointerTarget(ctx, rangeValue, rangeType)
3852
- indexTarget := o.lowerIndexTarget(ctx, rangeValue, rangeType)
5181
+ rangeTarget := ctx.tempName("RangeTarget")
5182
+ rangeTargetValue := o.lowerArrayPointerTarget(ctx, rangeValue, rangeType)
5183
+ indexTarget := rangeTarget
5184
+ if isNilableType(rangeType) {
5185
+ indexTarget += "!"
5186
+ }
3853
5187
  indexName := keyName
3854
5188
  if indexName == "" {
3855
5189
  indexName = "__rangeIndex"
@@ -3864,7 +5198,7 @@ func (o *LoweringOwner) lowerRangeStmt(ctx lowerFileContext, stmt *ast.RangeStmt
3864
5198
  }
3865
5199
  return loweredStmt{
3866
5200
  hasBlock: true,
3867
- text: "for (let " + indexName + " = 0; " + indexName + " < " + o.runtimeOwner.QualifiedHelper(RuntimeHelperLen) + "(" + rangeTarget + "); " + indexName + "++)",
5201
+ text: "for (let " + rangeTarget + " = " + rangeTargetValue + ", " + indexName + " = 0; " + indexName + " < " + o.runtimeOwner.QualifiedHelper(RuntimeHelperLen) + "(" + rangeTarget + "); " + indexName + "++)",
3868
5202
  children: children,
3869
5203
  }, diagnostics
3870
5204
  }
@@ -3933,18 +5267,19 @@ func (o *LoweringOwner) lowerRangeFuncStmt(
3933
5267
  rangeBranch.value = ctx.tempName("RangeReturnValue")
3934
5268
  rangeBranch.resultType = o.tsSignatureResultFor(ctx, ctx.signature)
3935
5269
  }
3936
- body, diagnostics := o.lowerBlock(ctx.withRangeBranch(rangeBranch), stmt.Body)
5270
+ body, diagnostics := o.lowerBlock(ctx.withoutLoopLabel().withRangeBranch(rangeBranch), stmt.Body)
3937
5271
  if stmt.Tok != token.DEFINE {
3938
5272
  assignments, assignmentDiagnostics := o.lowerRangeFuncAssignments(ctx, stmt, paramNames)
3939
5273
  diagnostics = append(diagnostics, assignmentDiagnostics...)
3940
5274
  body = append(assignments, body...)
3941
5275
  }
5276
+ async := ctx.asyncFunction
3942
5277
 
3943
5278
  return loweredStmt{rangeFunc: &loweredRangeFunc{
3944
5279
  value: rangeValue,
3945
5280
  params: paramNames,
3946
5281
  body: body,
3947
- async: stmtsContainAwait(body) || o.rangeFunctionValueNeedsAwait(ctx, stmt.X),
5282
+ async: async,
3948
5283
  returnBranch: rangeBranch,
3949
5284
  parentBranch: parentBranch,
3950
5285
  }}, diagnostics
@@ -3989,6 +5324,7 @@ func (o *LoweringOwner) lowerSelectStmt(ctx lowerFileContext, stmt *ast.SelectSt
3989
5324
  lowered := &loweredSelect{
3990
5325
  hasReturn: selectName + "HasReturn",
3991
5326
  value: selectName + "Value",
5327
+ result: selectName + "Result",
3992
5328
  resultType: resultType,
3993
5329
  }
3994
5330
  var diagnostics []Diagnostic
@@ -4025,7 +5361,7 @@ func (o *LoweringOwner) lowerSelectStmt(ctx lowerFileContext, stmt *ast.SelectSt
4025
5361
  })
4026
5362
  caseID++
4027
5363
  case *ast.ExprStmt:
4028
- channel, prelude, receiveDiagnostics := o.lowerSelectReceiveComm(ctx, nil, comm.X)
5364
+ channel, prelude, receiveDiagnostics := o.lowerSelectReceiveComm(ctx, nil, comm.X, lowered.result)
4029
5365
  body, bodyDiagnostics := o.lowerStmtList(ctx.withLocalScope().withoutRangeBreak(), clause.Body)
4030
5366
  diagnostics = append(diagnostics, receiveDiagnostics...)
4031
5367
  diagnostics = append(diagnostics, bodyDiagnostics...)
@@ -4037,7 +5373,7 @@ func (o *LoweringOwner) lowerSelectStmt(ctx lowerFileContext, stmt *ast.SelectSt
4037
5373
  })
4038
5374
  caseID++
4039
5375
  case *ast.AssignStmt:
4040
- channel, prelude, receiveDiagnostics := o.lowerSelectReceiveComm(ctx, comm, nil)
5376
+ channel, prelude, receiveDiagnostics := o.lowerSelectReceiveComm(ctx, comm, nil, lowered.result)
4041
5377
  body, bodyDiagnostics := o.lowerStmtList(ctx.withLocalScope().withoutRangeBreak(), clause.Body)
4042
5378
  diagnostics = append(diagnostics, receiveDiagnostics...)
4043
5379
  diagnostics = append(diagnostics, bodyDiagnostics...)
@@ -4083,11 +5419,22 @@ func stmtsEndInReturn(stmts []loweredStmt) bool {
4083
5419
  return false
4084
5420
  }
4085
5421
  last := stmts[len(stmts)-1]
4086
- if strings.HasPrefix(strings.TrimSpace(last.text), "return") {
5422
+ return stmtEndsInReturn(last)
5423
+ }
5424
+
5425
+ func stmtEndsInReturn(stmt loweredStmt) bool {
5426
+ trimmed := strings.TrimSpace(stmt.text)
5427
+ if strings.HasPrefix(trimmed, "return") {
4087
5428
  return true
4088
5429
  }
4089
- if last.selectStmt != nil {
4090
- return last.selectStmt.returns
5430
+ if stmt.selectStmt != nil {
5431
+ return stmt.selectStmt.returns
5432
+ }
5433
+ if trimmed == "" && (stmt.hasBlock || len(stmt.children) != 0) {
5434
+ return stmtsEndInReturn(stmt.children)
5435
+ }
5436
+ if strings.HasPrefix(trimmed, "if ") && len(stmt.elseBody) != 0 {
5437
+ return stmtsEndInReturn(stmt.children) && stmtsEndInReturn(stmt.elseBody)
4091
5438
  }
4092
5439
  return false
4093
5440
  }
@@ -4134,6 +5481,7 @@ func (o *LoweringOwner) lowerSelectReceiveComm(
4134
5481
  ctx lowerFileContext,
4135
5482
  assign *ast.AssignStmt,
4136
5483
  expr ast.Expr,
5484
+ resultName string,
4137
5485
  ) (string, []loweredStmt, []Diagnostic) {
4138
5486
  receiveExpr := expr
4139
5487
  if assign != nil && len(assign.Rhs) == 1 {
@@ -4162,7 +5510,7 @@ func (o *LoweringOwner) lowerSelectReceiveComm(
4162
5510
  if assign.Tok == token.DEFINE && isShortAssignTargetNew(ctx, lhs) {
4163
5511
  prefix = "let "
4164
5512
  }
4165
- prelude = append(prelude, loweredStmt{text: prefix + left + " = result" + fields[idx]})
5513
+ prelude = append(prelude, loweredStmt{text: prefix + left + " = " + resultName + fields[idx]})
4166
5514
  }
4167
5515
  return channel, prelude, diagnostics
4168
5516
  }
@@ -4177,15 +5525,24 @@ func (o *LoweringOwner) lowerSwitchStmt(ctx lowerFileContext, stmt *ast.SwitchSt
4177
5525
  }
4178
5526
 
4179
5527
  value := "true"
5528
+ var tagType types.Type
4180
5529
  if stmt.Tag != nil {
4181
5530
  var valueDiagnostics []Diagnostic
4182
5531
  value, valueDiagnostics = o.lowerExpr(ctx, stmt.Tag)
4183
5532
  diagnostics = append(diagnostics, valueDiagnostics...)
4184
5533
  value = lowerConstantComparableValue(ctx, stmt.Tag, value)
5534
+ tagType = ctx.semPkg.source.TypesInfo.TypeOf(stmt.Tag)
4185
5535
  } else if switchHasConstantCaseExpr(ctx, stmt) {
4186
5536
  value = "(true as boolean)"
4187
5537
  }
4188
5538
 
5539
+ compareCases := tagType != nil && isInterfaceType(tagType)
5540
+ compareValue := value
5541
+ if compareCases {
5542
+ compareValue = ctx.tempName("Switch")
5543
+ init = append(init, loweredStmt{text: "let " + compareValue + " = " + value})
5544
+ value = "true"
5545
+ }
4189
5546
  switchIR := &loweredSwitch{value: value}
4190
5547
  for _, raw := range stmt.Body.List {
4191
5548
  clause, ok := raw.(*ast.CaseClause)
@@ -4207,6 +5564,11 @@ func (o *LoweringOwner) lowerSwitchStmt(ctx lowerFileContext, stmt *ast.SwitchSt
4207
5564
  for _, expr := range clause.List {
4208
5565
  lowered, exprDiagnostics := o.lowerExpr(ctx, expr)
4209
5566
  diagnostics = append(diagnostics, exprDiagnostics...)
5567
+ if compareCases {
5568
+ sourceType := ctx.semPkg.source.TypesInfo.TypeOf(expr)
5569
+ lowered = o.lowerValueForTargetTypes(ctx, tagType, sourceType, lowered, shouldCloneStructValue(expr))
5570
+ lowered = o.runtimeOwner.QualifiedHelper(RuntimeHelperComparableEqual) + "(" + compareValue + ", " + lowered + ")"
5571
+ }
4210
5572
  values = append(values, lowered)
4211
5573
  }
4212
5574
  switchIR.cases = append(switchIR.cases, loweredSwitchCase{
@@ -4309,7 +5671,7 @@ func (o *LoweringOwner) lowerTypeSwitchStmt(ctx lowerFileContext, stmt *ast.Type
4309
5671
  if typ == nil {
4310
5672
  tsTypes = append(tsTypes, "any")
4311
5673
  } else {
4312
- tsTypes = append(tsTypes, o.tsTypeFor(ctx, typ))
5674
+ tsTypes = append(tsTypes, o.tsTypeSwitchCaseTypeFor(ctx, typ))
4313
5675
  }
4314
5676
  }
4315
5677
  switchIR.cases = append(switchIR.cases, loweredTypeSwitchCase{
@@ -4323,6 +5685,15 @@ func (o *LoweringOwner) lowerTypeSwitchStmt(ctx lowerFileContext, stmt *ast.Type
4323
5685
  return lowered, diagnostics
4324
5686
  }
4325
5687
 
5688
+ func (o *LoweringOwner) tsTypeSwitchCaseTypeFor(ctx lowerFileContext, typ types.Type) string {
5689
+ if named, ok := types.Unalias(typ).(*types.Named); ok {
5690
+ if _, ok := named.Underlying().(*types.Interface); ok {
5691
+ return o.tsNonNilTypeFor(ctx, named)
5692
+ }
5693
+ }
5694
+ return o.tsTypeFor(ctx, typ)
5695
+ }
5696
+
4326
5697
  func loweredStmtsUseVarRefName(stmts []loweredStmt, name string) bool {
4327
5698
  if name == "" {
4328
5699
  return false
@@ -4518,7 +5889,108 @@ func (o *LoweringOwner) lowerArrayEqualityExpr(ctx lowerFileContext, expr *ast.B
4518
5889
  return value, true
4519
5890
  }
4520
5891
 
5892
+ func (o *LoweringOwner) lowerComplexEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
5893
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5894
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
5895
+ if !isComplexType(leftType) || !isComplexType(rightType) {
5896
+ return "", false
5897
+ }
5898
+ value := o.runtimeOwner.QualifiedHelper(RuntimeHelperArrayEqual) + "(" + left + ", " + right + ")"
5899
+ if expr.Op == token.NEQ {
5900
+ value = "!" + value
5901
+ }
5902
+ return value, true
5903
+ }
5904
+
5905
+ func (o *LoweringOwner) lowerStringEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
5906
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5907
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
5908
+ if !isStringType(leftType) || !isStringType(rightType) {
5909
+ return "", false
5910
+ }
5911
+ value := o.runtimeOwner.QualifiedHelper(RuntimeHelperStringEqual) + "(" + left + ", " + right + ")"
5912
+ if expr.Op == token.NEQ {
5913
+ value = "!" + value
5914
+ }
5915
+ return value, true
5916
+ }
5917
+
5918
+ func (o *LoweringOwner) lowerInterfaceEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
5919
+ if isNilExpr(expr.X) || isNilExpr(expr.Y) {
5920
+ return "", false
5921
+ }
5922
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5923
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
5924
+ if !isInterfaceType(leftType) && !isInterfaceType(rightType) {
5925
+ return "", false
5926
+ }
5927
+ value := o.runtimeOwner.QualifiedHelper(RuntimeHelperComparableEqual) + "(" + left + ", " + right + ")"
5928
+ if expr.Op == token.NEQ {
5929
+ value = "!" + value
5930
+ }
5931
+ return value, true
5932
+ }
5933
+
5934
+ func (o *LoweringOwner) lowerStringOrderExpr(
5935
+ ctx lowerFileContext,
5936
+ expr *ast.BinaryExpr,
5937
+ left string,
5938
+ right string,
5939
+ leftDiagnostics []Diagnostic,
5940
+ rightDiagnostics []Diagnostic,
5941
+ ) (string, []Diagnostic, bool) {
5942
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5943
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
5944
+ if !isStringType(leftType) || !isStringType(rightType) {
5945
+ return "", nil, false
5946
+ }
5947
+ left, leftDiagnostics = o.lowerStringOrderOperand(ctx, expr.X, left, leftDiagnostics)
5948
+ right, rightDiagnostics = o.lowerStringOrderOperand(ctx, expr.Y, right, rightDiagnostics)
5949
+ compare := o.runtimeOwner.QualifiedHelper(RuntimeHelperStringCompare) + "(" + left + ", " + right + ")"
5950
+ switch expr.Op {
5951
+ case token.LSS:
5952
+ return compare + " < 0", append(leftDiagnostics, rightDiagnostics...), true
5953
+ case token.LEQ:
5954
+ return compare + " <= 0", append(leftDiagnostics, rightDiagnostics...), true
5955
+ case token.GTR:
5956
+ return compare + " > 0", append(leftDiagnostics, rightDiagnostics...), true
5957
+ case token.GEQ:
5958
+ return compare + " >= 0", append(leftDiagnostics, rightDiagnostics...), true
5959
+ default:
5960
+ return "", nil, false
5961
+ }
5962
+ }
5963
+
5964
+ func (o *LoweringOwner) lowerStringOrderOperand(
5965
+ ctx lowerFileContext,
5966
+ expr ast.Expr,
5967
+ fallback string,
5968
+ fallbackDiagnostics []Diagnostic,
5969
+ ) (string, []Diagnostic) {
5970
+ call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
5971
+ if !ok || len(call.Args) != 1 {
5972
+ return fallback, fallbackDiagnostics
5973
+ }
5974
+ targetType := typeFromExpr(ctx, call.Fun)
5975
+ sourceType := ctx.semPkg.source.TypesInfo.TypeOf(call.Args[0])
5976
+ if targetType == nil || sourceType == nil || !isStringType(targetType) || !isByteSliceType(sourceType) {
5977
+ return fallback, fallbackDiagnostics
5978
+ }
5979
+ return o.lowerExpr(ctx, call.Args[0])
5980
+ }
5981
+
5982
+ func binaryOperandUsesTypeParam(ctx lowerFileContext, expr ast.Expr) bool {
5983
+ typ := ctx.semPkg.source.TypesInfo.TypeOf(expr)
5984
+ _, ok := types.Unalias(typ).(*types.TypeParam)
5985
+ return ok
5986
+ }
5987
+
4521
5988
  func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
5989
+ if value := ctx.semPkg.source.TypesInfo.Types[unwrapParenExpr(expr)].Value; value != nil && value.Kind() == constant.Complex {
5990
+ if constantValue, ok := lowerConstantValue(value); ok {
5991
+ return constantValue, nil
5992
+ }
5993
+ }
4522
5994
  switch typed := expr.(type) {
4523
5995
  case *ast.BasicLit:
4524
5996
  return lowerBasicLit(typed), nil
@@ -4526,6 +5998,11 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
4526
5998
  return o.lowerIdent(ctx, typed, false), nil
4527
5999
  case *ast.BinaryExpr:
4528
6000
  if value := ctx.semPkg.source.TypesInfo.Types[typed].Value; value != nil {
6001
+ if (typed.Op == token.SHL || typed.Op == token.SHR) && (value.Kind() == constant.Int || value.Kind() == constant.Float) {
6002
+ if constantValue, ok := lowerConstantValue(value); ok {
6003
+ return constantValue, nil
6004
+ }
6005
+ }
4529
6006
  if constantValue, ok := lowerLargeIntegerConstantValue(value); ok {
4530
6007
  return constantValue, nil
4531
6008
  }
@@ -4550,8 +6027,20 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
4550
6027
  if value, ok := o.lowerArrayEqualityExpr(ctx, typed, left, right); ok {
4551
6028
  return value, append(leftDiagnostics, rightDiagnostics...)
4552
6029
  }
6030
+ if value, ok := o.lowerComplexEqualityExpr(ctx, typed, left, right); ok {
6031
+ return value, append(leftDiagnostics, rightDiagnostics...)
6032
+ }
6033
+ if value, ok := o.lowerStringEqualityExpr(ctx, typed, left, right); ok {
6034
+ return value, append(leftDiagnostics, rightDiagnostics...)
6035
+ }
6036
+ if value, ok := o.lowerInterfaceEqualityExpr(ctx, typed, left, right); ok {
6037
+ return value, append(leftDiagnostics, rightDiagnostics...)
6038
+ }
4553
6039
  left, right = o.lowerEqualityOperands(ctx, typed, left, right)
4554
6040
  }
6041
+ if value, ok := o.lowerWideIntegerBinaryExpr(ctx, typed, left, right); ok {
6042
+ return value, append(leftDiagnostics, rightDiagnostics...)
6043
+ }
4555
6044
  if typed.Op == token.QUO && isIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(typed)) {
4556
6045
  return "Math.trunc(" + left + " / " + right + ")", append(leftDiagnostics, rightDiagnostics...)
4557
6046
  }
@@ -4561,8 +6050,14 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
4561
6050
  "(" + left + ", " + right + ", " + strconv.Itoa(bits) + ")", append(leftDiagnostics, rightDiagnostics...)
4562
6051
  }
4563
6052
  }
4564
- if value, ok := o.lowerWideIntegerBinaryExpr(ctx, typed, left, right); ok {
4565
- return value, append(leftDiagnostics, rightDiagnostics...)
6053
+ if value, diagnostics, ok := o.lowerStringOrderExpr(ctx, typed, left, right, leftDiagnostics, rightDiagnostics); ok {
6054
+ return value, diagnostics
6055
+ }
6056
+ if binaryOperandUsesTypeParam(ctx, typed.X) {
6057
+ left = "(" + left + " as any)"
6058
+ }
6059
+ if binaryOperandUsesTypeParam(ctx, typed.Y) {
6060
+ right = "(" + right + " as any)"
4566
6061
  }
4567
6062
  return left + " " + typed.Op.String() + " " + right, append(leftDiagnostics, rightDiagnostics...)
4568
6063
  case *ast.UnaryExpr:
@@ -4575,7 +6070,7 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
4575
6070
  }
4576
6071
  value, diagnostics := o.lowerExpr(ctx, typed.X)
4577
6072
  if typed.Op == token.NOT || typed.Op == token.SUB || typed.Op == token.ADD {
4578
- return typed.Op.String() + value, diagnostics
6073
+ return lowerPrefixUnaryExpr(typed.Op, value), diagnostics
4579
6074
  }
4580
6075
  if typed.Op == token.XOR {
4581
6076
  return "~" + value, diagnostics
@@ -4621,7 +6116,7 @@ func lowerBasicLit(lit *ast.BasicLit) string {
4621
6116
  if err != nil {
4622
6117
  return strconv.Quote(lit.Value)
4623
6118
  }
4624
- return strconv.Quote(value)
6119
+ return lowerGoStringLiteral(value)
4625
6120
  }
4626
6121
  if lit.Kind == token.INT && isLegacyOctalLiteral(lit.Value) {
4627
6122
  digits := strings.TrimLeft(strings.ReplaceAll(lit.Value, "_", ""), "0")
@@ -4665,8 +6160,17 @@ func (o *LoweringOwner) lowerFuncLit(ctx lowerFileContext, lit *ast.FuncLit) (st
4665
6160
  if asyncCompatibleParams || funcLiteralUsesFunctionIdentifierCall(ctx, lit) {
4666
6161
  bodyCtx = bodyCtx.withAsyncFunction(true)
4667
6162
  }
6163
+ var params []loweredParam
6164
+ var paramBindings []loweredStmt
6165
+ if signature != nil && signature.Params() != nil {
6166
+ for idx := range signature.Params().Len() {
6167
+ param := signature.Params().At(idx)
6168
+ params, paramBindings = o.appendLoweredParam(ctx, params, paramBindings, param, idx, asyncCompatibleParams)
6169
+ }
6170
+ }
4668
6171
  body, diagnostics := o.lowerBlock(bodyCtx, lit.Body)
4669
6172
  var rendered strings.Builder
6173
+ renderStmts(&rendered, paramBindings, 1)
4670
6174
  renderNamedResults(&rendered, o.lowerNamedResults(ctx, signature), 1)
4671
6175
  renderDeferStack(&rendered, deferState, 1)
4672
6176
  renderStmts(&rendered, body, 1)
@@ -4675,21 +6179,28 @@ func (o *LoweringOwner) lowerFuncLit(ctx lowerFileContext, lit *ast.FuncLit) (st
4675
6179
  if async {
4676
6180
  prefix = "async "
4677
6181
  }
4678
- function := prefix + "(" + o.tsSignatureParamsFor(ctx, signature, asyncCompatibleParams) + "): " +
6182
+ function := prefix + "(" + renderLoweredParams(params) + "): " +
4679
6183
  asyncResultType(o.tsSignatureResultFor(ctx, signature), async) + " => {\n" +
4680
6184
  rendered.String() + "}"
4681
6185
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperFunctionValue) +
4682
6186
  "(" + function + ", " + o.runtimeFunctionTypeInfo(signature, "") + ")", async, diagnostics
4683
6187
  }
4684
6188
 
6189
+ func renderLoweredParams(params []loweredParam) string {
6190
+ if len(params) == 0 {
6191
+ return ""
6192
+ }
6193
+ rendered := make([]string, 0, len(params))
6194
+ for _, param := range params {
6195
+ rendered = append(rendered, param.name+": "+param.typ)
6196
+ }
6197
+ return strings.Join(rendered, ", ")
6198
+ }
6199
+
4685
6200
  func funcLiteralUsesFunctionIdentifierCall(ctx lowerFileContext, lit *ast.FuncLit) bool {
4686
6201
  if lit == nil || lit.Body == nil || ctx.semPkg == nil || ctx.semPkg.source == nil {
4687
6202
  return false
4688
6203
  }
4689
- signature, _ := ctx.semPkg.source.TypesInfo.TypeOf(lit).(*types.Signature)
4690
- if signature == nil || signature.Results() == nil || signature.Results().Len() == 0 {
4691
- return false
4692
- }
4693
6204
  uses := false
4694
6205
  ast.Inspect(lit.Body, func(node ast.Node) bool {
4695
6206
  if uses {
@@ -4760,6 +6271,9 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
4760
6271
  }
4761
6272
  obj := objectForIdent(ctx, ident)
4762
6273
  if alias := ctx.identAliases[obj]; alias != "" {
6274
+ if !raw && obj != nil && ctx.identAliasRefs[obj] && ctx.model.needsVarRef[obj] {
6275
+ return alias + ".value"
6276
+ }
4763
6277
  return alias
4764
6278
  }
4765
6279
  if constObj, ok := obj.(*types.Const); ok && ctx.localAliases[obj] != "" {
@@ -4770,22 +6284,28 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
4770
6284
  if alias := ctx.localAliases[obj]; alias != "" {
4771
6285
  if ctx.lazyPackageVars[obj] {
4772
6286
  lazyValue := alias + "." + packageVarGetterName(value) + "()"
4773
- if obj != nil && ctx.model.needsVarRef[obj] {
4774
- return lazyValue + ".value"
6287
+ if (ctx.asyncFunction || ctx.topLevel) && o.packageVarHasAsyncLazyInit(ctx, obj) {
6288
+ lazyValue = "(await " + alias + "." + packageVarInitName(value) + "(), " + lazyValue + ")"
6289
+ }
6290
+ if raw {
6291
+ return lazyValue
4775
6292
  }
4776
- return lazyValue
6293
+ return o.lowerPackageVarReadValue(ctx, obj, lazyValue)
4777
6294
  }
4778
- return alias + "." + value
6295
+ if raw {
6296
+ return alias + "." + value
6297
+ }
6298
+ return o.lowerPackageVarReadValue(ctx, obj, alias+"."+value)
4779
6299
  }
4780
6300
  if raw {
4781
6301
  return value
4782
6302
  }
4783
6303
  if ctx.lazyPackageVars[obj] {
4784
6304
  lazyValue := packageVarGetterName(value) + "()"
4785
- if obj != nil && ctx.model.needsVarRef[obj] {
4786
- return lazyValue + ".value"
6305
+ if (ctx.asyncFunction || ctx.topLevel) && o.packageVarHasAsyncLazyInit(ctx, obj) {
6306
+ lazyValue = "(await " + packageVarInitName(value) + "(), " + lazyValue + ")"
4787
6307
  }
4788
- return lazyValue
6308
+ return o.lowerPackageVarReadValue(ctx, obj, lazyValue)
4789
6309
  }
4790
6310
  if obj != nil && ctx.model.needsVarRef[obj] {
4791
6311
  return value + ".value"
@@ -4793,6 +6313,17 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
4793
6313
  return value
4794
6314
  }
4795
6315
 
6316
+ func (o *LoweringOwner) lowerPackageVarReadValue(ctx lowerFileContext, obj types.Object, value string) string {
6317
+ if obj == nil || ctx.model == nil || !ctx.model.needsVarRef[obj] {
6318
+ return value
6319
+ }
6320
+ if varObj, ok := obj.(*types.Var); ok && packageVarReadNeedsPointerValue(varObj.Type()) {
6321
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
6322
+ "<" + o.tsNonNilTypeFor(ctx, varObj.Type()) + ">(" + value + ")"
6323
+ }
6324
+ return value + ".value"
6325
+ }
6326
+
4796
6327
  func objectForIdent(ctx lowerFileContext, ident *ast.Ident) types.Object {
4797
6328
  if ctx.semPkg == nil || ctx.semPkg.source == nil {
4798
6329
  return nil
@@ -4820,6 +6351,28 @@ func objectForValueExpr(ctx lowerFileContext, expr ast.Expr) types.Object {
4820
6351
  }
4821
6352
  }
4822
6353
 
6354
+ func objectNeedsVarRef(ctx lowerFileContext, obj types.Object) bool {
6355
+ if obj == nil || ctx.model == nil {
6356
+ return false
6357
+ }
6358
+ if ctx.model.needsVarRef[obj] {
6359
+ return true
6360
+ }
6361
+ if obj.Pkg() == nil {
6362
+ return false
6363
+ }
6364
+ semPkg := ctx.model.packages[obj.Pkg().Path()]
6365
+ if semPkg == nil {
6366
+ return false
6367
+ }
6368
+ for _, value := range semPkg.values {
6369
+ if value.name == obj.Name() && ctx.model.needsVarRef[value.object] {
6370
+ return true
6371
+ }
6372
+ }
6373
+ return false
6374
+ }
6375
+
4823
6376
  func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr) (string, []Diagnostic) {
4824
6377
  if ident, ok := expr.Fun.(*ast.Ident); ok && isBuiltinCallTarget(ctx, ident) {
4825
6378
  switch ident.Name {
@@ -4846,6 +6399,22 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
4846
6399
  }
4847
6400
  return o.runtimeOwner.QualifiedHelper(helper) + "(" + strings.Join(args, ", ") + ")", diagnostics
4848
6401
  case "append":
6402
+ if len(expr.Args) > 0 {
6403
+ if slice, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(expr.Args[0])).Underlying().(*types.Slice); ok {
6404
+ for idx := 1; idx < len(args); idx++ {
6405
+ if expr.Ellipsis != token.NoPos && idx == len(args)-1 {
6406
+ continue
6407
+ }
6408
+ args[idx] = o.lowerValueForTargetTypes(
6409
+ ctx,
6410
+ slice.Elem(),
6411
+ ctx.semPkg.source.TypesInfo.TypeOf(expr.Args[idx]),
6412
+ args[idx],
6413
+ false,
6414
+ )
6415
+ }
6416
+ }
6417
+ }
4849
6418
  if expr.Ellipsis != token.NoPos && len(args) > 1 {
4850
6419
  last := len(args) - 1
4851
6420
  spread := args[last]
@@ -4854,7 +6423,13 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
4854
6423
  }
4855
6424
  args[last] = "...(" + spread + " ?? [])"
4856
6425
  }
4857
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperAppend) + "(" + strings.Join(args, ", ") + ")", diagnostics
6426
+ appendHelper := o.runtimeOwner.QualifiedHelper(RuntimeHelperAppend)
6427
+ if len(args) > 0 && args[0] == "null" {
6428
+ if slice, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(expr)).Underlying().(*types.Slice); ok {
6429
+ appendHelper += "<" + o.tsTypeFor(ctx, slice.Elem()) + ">"
6430
+ }
6431
+ }
6432
+ return appendHelper + "(" + strings.Join(args, ", ") + ")", diagnostics
4858
6433
  case "cap":
4859
6434
  if len(expr.Args) == 1 {
4860
6435
  args[0] = o.lowerArrayPointerTarget(ctx, args[0], ctx.semPkg.source.TypesInfo.TypeOf(expr.Args[0]))
@@ -4906,7 +6481,7 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
4906
6481
  if typeParam := receiverTypeParam(selection.Recv()); typeParam != nil {
4907
6482
  receiverExpr, receiverDiagnostics := o.lowerExpr(ctx, fun.X)
4908
6483
  diagnostics = append(diagnostics, receiverDiagnostics...)
4909
- if !signatureHasTypeParam(ctx.signature, typeParam) {
6484
+ if !typeParamInScope(ctx, typeParam) {
4910
6485
  call := receiverExpr + "." + fun.Sel.Name + "(" + strings.Join(args, ", ") + ")"
4911
6486
  return o.awaitCallIfNeeded(ctx, fun, call), diagnostics
4912
6487
  }
@@ -4914,11 +6489,14 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
4914
6489
  call := o.runtimeOwner.QualifiedHelper(RuntimeHelperCallGenericMethod) + "(" + strings.Join(methodArgs, ", ") + ")"
4915
6490
  return o.awaitCallIfNeeded(ctx, fun, call), diagnostics
4916
6491
  }
4917
- receiver := receiverNamedType(selection.Recv())
6492
+ receiver := methodReceiverNamedType(selection.Obj())
6493
+ if receiver == nil {
6494
+ receiver = receiverNamedType(selection.Recv())
6495
+ }
4918
6496
  if namedNonInterfaceNonStructType(receiver) {
4919
6497
  return o.lowerNamedReceiverMethodCall(ctx, fun, args, diagnostics)
4920
6498
  }
4921
- if call, callDiagnostics, ok := o.lowerNilablePointerReceiverMethodCall(ctx, fun, selection, args); ok {
6499
+ if call, callDiagnostics, ok := o.lowerPointerReceiverMethodCall(ctx, fun, selection, args); ok {
4922
6500
  return o.awaitCallIfNeeded(ctx, fun, call), append(diagnostics, callDiagnostics...)
4923
6501
  }
4924
6502
  receiverExpr, receiverDiagnostics := o.lowerMethodReceiverExpr(ctx, fun.X, selection)
@@ -5024,6 +6602,7 @@ func (o *LoweringOwner) lowerCallArgs(
5024
6602
  lowered = o.lowerCallArgForTarget(ctx, arg, params.At(idx).Type(), lowered, overrideCall)
5025
6603
  } else if expr.Ellipsis != token.NoPos && idx == len(expr.Args)-1 {
5026
6604
  lowered = o.lowerCallArgForTarget(ctx, arg, params.At(fixedCount).Type(), lowered, overrideCall)
6605
+ lowered = "...(" + lowered + " ?? [])"
5027
6606
  } else {
5028
6607
  lowered = o.lowerCallArgForTarget(ctx, arg, targetType, lowered, overrideCall)
5029
6608
  }
@@ -5107,19 +6686,41 @@ func (o *LoweringOwner) lowerTupleCallArgs(
5107
6686
  parts = append(parts, converted)
5108
6687
  }
5109
6688
  if !changed {
5110
- return []string{"...(" + value + ")"}, diagnostics, true
6689
+ return []string{"...(" + o.parenthesizedTupleCast(ctx, value, params) + ")"}, diagnostics, true
5111
6690
  }
5112
6691
  temp := ctx.tempName("TupleArg")
5113
6692
  for idx, part := range parts {
5114
6693
  parts[idx] = strings.ReplaceAll(part, "__goscriptTupleArg", temp)
5115
6694
  }
5116
- body := "const " + temp + " = " + value + "; return [" + strings.Join(parts, ", ") + "]"
6695
+ body := "const " + temp + " = " + value + "; return " + o.tupleLiteralCast(ctx, params, parts)
5117
6696
  if strings.Contains(value, "await ") {
5118
6697
  return []string{"...(await (async () => { " + body + " })())"}, diagnostics, true
5119
6698
  }
5120
6699
  return []string{"...(() => { " + body + " })()"}, diagnostics, true
5121
6700
  }
5122
6701
 
6702
+ func (o *LoweringOwner) parenthesizedTupleCast(ctx lowerFileContext, value string, params *types.Tuple) string {
6703
+ if strings.HasPrefix(value, "await ") {
6704
+ return "(" + value + ") as " + o.tupleTypeForParams(ctx, params)
6705
+ }
6706
+ return value + " as " + o.tupleTypeForParams(ctx, params)
6707
+ }
6708
+
6709
+ func (o *LoweringOwner) tupleLiteralCast(ctx lowerFileContext, params *types.Tuple, parts []string) string {
6710
+ return "[" + strings.Join(parts, ", ") + "] as " + o.tupleTypeForParams(ctx, params)
6711
+ }
6712
+
6713
+ func (o *LoweringOwner) tupleTypeForParams(ctx lowerFileContext, params *types.Tuple) string {
6714
+ if params == nil || params.Len() == 0 {
6715
+ return "[]"
6716
+ }
6717
+ parts := make([]string, 0, params.Len())
6718
+ for v := range params.Variables() {
6719
+ parts = append(parts, o.tsTypeFor(ctx, v.Type()))
6720
+ }
6721
+ return "[" + strings.Join(parts, ", ") + "]"
6722
+ }
6723
+
5123
6724
  func (o *LoweringOwner) lowerFixedCallArgs(
5124
6725
  ctx lowerFileContext,
5125
6726
  exprs []ast.Expr,
@@ -5153,7 +6754,7 @@ func (o *LoweringOwner) lowerCallArgForTarget(
5153
6754
  value = o.lowerValueForTarget(ctx, expr, targetType, value)
5154
6755
  sourceType := ctx.semPkg.source.TypesInfo.TypeOf(expr)
5155
6756
  if overrideCall && isNonEmptyInterfaceType(targetType) && (isInterfaceType(sourceType) || isNilableType(sourceType)) {
5156
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + "(" + value + ")"
6757
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValueOrNil) + "(" + value + ")!"
5157
6758
  }
5158
6759
  return value
5159
6760
  }
@@ -5293,7 +6894,7 @@ func (o *LoweringOwner) lowerMakeExpr(ctx lowerFileContext, expr *ast.CallExpr)
5293
6894
  args = append(args, "() => "+o.lowerZeroValueExprFor(ctx, typed.Elem()))
5294
6895
  }
5295
6896
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperMakeSlice) +
5296
- "<" + o.tsTypeFor(ctx, typed.Elem()) + ">(" + strings.Join(args, ", ") + ")", diagnostics
6897
+ "<" + o.tsSliceElemTypeFor(ctx, typed.Elem()) + ">(" + strings.Join(args, ", ") + ")", diagnostics
5297
6898
  case *types.Map:
5298
6899
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperMakeMap) +
5299
6900
  "<" + o.tsTypeFor(ctx, typed.Key()) + ", " + o.tsTypeFor(ctx, typed.Elem()) + ">()", nil
@@ -5321,7 +6922,8 @@ func (o *LoweringOwner) lowerNewExpr(ctx lowerFileContext, expr *ast.CallExpr) (
5321
6922
  if named := namedStructType(typ); named != nil {
5322
6923
  return "new " + o.namedTypeExpr(ctx, named) + "()", nil
5323
6924
  }
5324
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(" + o.lowerZeroValueExprFor(ctx, typ) + ")", nil
6925
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) +
6926
+ "<" + o.tsTypeFor(ctx, typ) + ">(" + o.lowerDeclarationZeroValueExpr(ctx, typ) + ")", nil
5325
6927
  }
5326
6928
 
5327
6929
  func (o *LoweringOwner) lowerConversionExpr(
@@ -5339,12 +6941,17 @@ func (o *LoweringOwner) lowerConversionExpr(
5339
6941
  return value, append(diagnostics, addressDiagnostics...)
5340
6942
  }
5341
6943
  }
6944
+ if helper, addressDiagnostics, ok := o.lowerReflectHeaderPointerConversion(ctx, targetType, expr.Args[0]); ok {
6945
+ return helper, append(diagnostics, addressDiagnostics...)
6946
+ }
6947
+ if helper, addressDiagnostics, ok := o.lowerUnsafeArrayPointerConversion(ctx, targetType, expr.Args[0]); ok {
6948
+ return helper, append(diagnostics, addressDiagnostics...)
6949
+ }
5342
6950
  if isUnsafePointerType(targetType) {
5343
6951
  return "(" + value + " as any)", diagnostics
5344
6952
  }
5345
6953
  if isNilExpr(expr.Args[0]) && isPointerType(targetType) {
5346
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperTypedNil) +
5347
- "(" + strconv.Quote(goRuntimeTypeString(targetType)) + ")", diagnostics
6954
+ return "null", diagnostics
5348
6955
  }
5349
6956
  if isInterfaceType(targetType) {
5350
6957
  return o.lowerValueForTarget(ctx, expr.Args[0], targetType, value), diagnostics
@@ -5402,6 +7009,13 @@ func (o *LoweringOwner) lowerConversionExpr(
5402
7009
  return result, diagnostics
5403
7010
  }
5404
7011
  }
7012
+ if target := pointerToNamedStructType(targetType); target != nil {
7013
+ source := pointerToNamedStructType(sourceType)
7014
+ if source != nil && !types.Identical(target, source) &&
7015
+ types.IdenticalIgnoreTags(target.Underlying(), source.Underlying()) {
7016
+ return "(" + value + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics
7017
+ }
7018
+ }
5405
7019
  if conversion, ok := o.lowerNamedStructConversion(ctx, expr.Args[0], targetType, sourceType, value); ok {
5406
7020
  return renderNamedStructConversion(conversion), diagnostics
5407
7021
  }
@@ -5421,6 +7035,9 @@ func (o *LoweringOwner) lowerConversionExpr(
5421
7035
  return value, diagnostics
5422
7036
  }
5423
7037
  if isNumericType(targetType) {
7038
+ if isFloatType(targetType) {
7039
+ return value, diagnostics
7040
+ }
5424
7041
  if bits, ok := unsignedIntegerBits(targetType); ok {
5425
7042
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
5426
7043
  "(" + value + ", " + strconv.Itoa(bits) + ")", diagnostics
@@ -5440,45 +7057,64 @@ func (o *LoweringOwner) lowerWideIntegerBinaryExpr(ctx lowerFileContext, expr *a
5440
7057
  if !resultWide && !leftWide {
5441
7058
  return "", false
5442
7059
  }
7060
+ signed := isFixedSignedWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr)) ||
7061
+ isFixedSignedWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
5443
7062
  switch expr.Op {
5444
7063
  case token.SHL, token.SHR:
5445
7064
  helper := RuntimeHelperUint64Shr
5446
7065
  if expr.Op == token.SHL {
5447
7066
  helper = RuntimeHelperUint64Shl
5448
7067
  }
7068
+ if signed {
7069
+ helper = RuntimeHelperInt64Shr
7070
+ if expr.Op == token.SHL {
7071
+ helper = RuntimeHelperInt64Shl
7072
+ }
7073
+ }
5449
7074
  if _, ok := constantShiftAmount(ctx, expr.Y); !ok {
5450
7075
  return o.runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")", true
5451
7076
  }
5452
7077
  amount, ok := constantShiftAmount(ctx, expr.Y)
5453
- if ok && amount >= 32 && expr.Op == token.SHL {
7078
+ if ok && amount >= 32 && expr.Op == token.SHL && !signed {
5454
7079
  base := o.lowerWideShiftLeftOperand(ctx, expr.X, left)
5455
7080
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Mul) +
5456
7081
  "(" + base + ", " + shiftMultiplier(amount) + ")", true
5457
7082
  }
5458
7083
  return o.runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")", true
5459
7084
  case token.MUL:
5460
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Mul) + "(" + left + ", " + right + ")", true
7085
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Mul, RuntimeHelperInt64Mul)) + "(" + left + ", " + right + ")", true
7086
+ case token.QUO:
7087
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Div, RuntimeHelperInt64Div)) + "(" + left + ", " + right + ")", true
7088
+ case token.REM:
7089
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Mod, RuntimeHelperInt64Mod)) + "(" + left + ", " + right + ")", true
5461
7090
  case token.ADD:
5462
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Add) + "(" + left + ", " + right + ")", true
7091
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Add, RuntimeHelperInt64Add)) + "(" + left + ", " + right + ")", true
5463
7092
  case token.SUB:
5464
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Sub) + "(" + left + ", " + right + ")", true
7093
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Sub, RuntimeHelperInt64Sub)) + "(" + left + ", " + right + ")", true
5465
7094
  case token.AND:
5466
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64And) + "(" + left + ", " + right + ")", true
7095
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64And, RuntimeHelperInt64And)) + "(" + left + ", " + right + ")", true
5467
7096
  case token.XOR:
5468
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Xor) + "(" + left + ", " + right + ")", true
7097
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Xor, RuntimeHelperInt64Xor)) + "(" + left + ", " + right + ")", true
5469
7098
  case token.OR:
5470
7099
  shift, ok := wideLeftShiftExpr(ctx, expr.X)
5471
- if ok {
7100
+ if ok && !signed {
5472
7101
  if bits, ok := lowIntegerBits(ctx, expr.Y); ok && bits <= shift {
5473
7102
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Add) + "(" + left + ", " + right + ")", true
5474
7103
  }
5475
7104
  }
5476
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Or) + "(" + left + ", " + right + ")", true
7105
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Or, RuntimeHelperInt64Or)) + "(" + left + ", " + right + ")", true
5477
7106
  default:
5478
7107
  return "", false
5479
7108
  }
5480
7109
  }
5481
7110
 
7111
+ func wideIntegerHelper(signed bool, unsigned RuntimeHelper, signedHelper RuntimeHelper) RuntimeHelper {
7112
+ if signed {
7113
+ return signedHelper
7114
+ }
7115
+ return unsigned
7116
+ }
7117
+
5482
7118
  func (o *LoweringOwner) lowerWideShiftLeftOperand(ctx lowerFileContext, expr ast.Expr, fallback string) string {
5483
7119
  call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
5484
7120
  if !ok || len(call.Args) != 1 {
@@ -5647,7 +7283,10 @@ func (o *LoweringOwner) lowerNamedReceiverMethodCall(
5647
7283
  diagnostics []Diagnostic,
5648
7284
  ) (string, []Diagnostic) {
5649
7285
  selection := ctx.semPkg.source.TypesInfo.Selections[selector]
5650
- receiver := receiverNamedType(selection.Recv())
7286
+ receiver := methodReceiverNamedType(selection.Obj())
7287
+ if receiver == nil {
7288
+ receiver = selectedReceiverNamedType(ctx.semPkg.source, selector, selection)
7289
+ }
5651
7290
  receiverExpr, receiverDiagnostics := o.lowerNamedReceiverForMethod(ctx, selector.X, selection)
5652
7291
  diagnostics = append(diagnostics, receiverDiagnostics...)
5653
7292
  allArgs := append([]string{receiverExpr}, args...)
@@ -5655,7 +7294,7 @@ func (o *LoweringOwner) lowerNamedReceiverMethodCall(
5655
7294
  return o.awaitCallIfNeeded(ctx, selector, call), diagnostics
5656
7295
  }
5657
7296
 
5658
- func (o *LoweringOwner) lowerNilablePointerReceiverMethodCall(
7297
+ func (o *LoweringOwner) lowerPointerReceiverMethodCall(
5659
7298
  ctx lowerFileContext,
5660
7299
  selector *ast.SelectorExpr,
5661
7300
  selection *types.Selection,
@@ -5668,9 +7307,6 @@ func (o *LoweringOwner) lowerNilablePointerReceiverMethodCall(
5668
7307
  if method == nil {
5669
7308
  return "", nil, false
5670
7309
  }
5671
- if !methodAllowsNilReceiver(ctx, method) {
5672
- return "", nil, false
5673
- }
5674
7310
  signature, _ := method.Type().(*types.Signature)
5675
7311
  if signature == nil || signature.Recv() == nil {
5676
7312
  return "", nil, false
@@ -5683,6 +7319,16 @@ func (o *LoweringOwner) lowerNilablePointerReceiverMethodCall(
5683
7319
  return "", nil, false
5684
7320
  }
5685
7321
  receiverExpr, diagnostics := o.lowerExpr(ctx, selector.X)
7322
+ if o.receiverUsesOverridePackage(signature.Recv().Type()) {
7323
+ receiverExpr = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
7324
+ "<" + o.tsTypeFor(ctx, signature.Recv().Type().(*types.Pointer).Elem()) + ">(" + receiverExpr + ")"
7325
+ }
7326
+ if receiverExpr == o.namedTypeExpr(ctx, receiver) {
7327
+ call := o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
7328
+ "<" + o.namedTypeExpr(ctx, receiver) + ">(" + receiverExpr + ")." +
7329
+ methodMemberName(selector.Sel.Name) + "(" + strings.Join(args, ", ") + ")"
7330
+ return call, diagnostics, true
7331
+ }
5686
7332
  callArgs := append([]string{receiverExpr}, args...)
5687
7333
  call := o.namedTypeExpr(ctx, receiver) + ".prototype." + selector.Sel.Name + ".call(" + strings.Join(callArgs, ", ") + ")"
5688
7334
  return call, diagnostics, true
@@ -5783,8 +7429,12 @@ func (o *LoweringOwner) lowerNamedReceiverForMethod(
5783
7429
  }
5784
7430
  return o.lowerAddressExpr(ctx, expr)
5785
7431
  }
5786
- receiver, diagnostics := o.lowerExpr(ctx, expr)
5787
- if receiverType != nil && isPointerType(ctx.semPkg.source.TypesInfo.TypeOf(expr)) {
7432
+ receiver, diagnostics := o.lowerMethodReceiverExpr(ctx, expr, selection)
7433
+ selectedType := ctx.semPkg.source.TypesInfo.TypeOf(expr)
7434
+ if index := selection.Index(); len(index) > 1 && !o.receiverUsesOverridePackage(selectedType) {
7435
+ selectedType = promotedMethodReceiverType(selectedType, index[:len(index)-1])
7436
+ }
7437
+ if receiverType != nil && isPointerType(selectedType) {
5788
7438
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + "<" + o.tsTypeFor(ctx, receiverType) + ">(" + receiver + ")", diagnostics
5789
7439
  }
5790
7440
  return receiver, diagnostics
@@ -5793,17 +7443,35 @@ func (o *LoweringOwner) lowerNamedReceiverForMethod(
5793
7443
  func (o *LoweringOwner) lowerSelectorExpr(ctx lowerFileContext, expr *ast.SelectorExpr) (string, []Diagnostic) {
5794
7444
  if ident, ok := expr.X.(*ast.Ident); ok {
5795
7445
  if pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName); pkgName != nil {
5796
- if alias := ctx.importNames[pkgName.Name()]; alias != "" {
5797
- return alias + "." + expr.Sel.Name, nil
7446
+ if alias := importAliasForPkgName(ctx, pkgName); alias != "" {
7447
+ value := alias + "." + expr.Sel.Name
7448
+ obj, _ := ctx.semPkg.source.TypesInfo.Uses[expr.Sel].(*types.Var)
7449
+ if o.packageVarIsLazy(ctx, obj) ||
7450
+ o.packageVarNameIsLazy(ctx, pkgName.Imported().Path(), expr.Sel.Name) {
7451
+ value = alias + "." + packageVarGetterName(expr.Sel.Name) + "()"
7452
+ if (ctx.asyncFunction || ctx.topLevel) &&
7453
+ o.packageVarNameHasAsyncLazyInit(ctx, pkgName.Imported().Path(), expr.Sel.Name) {
7454
+ value = "(await " + alias + "." + packageVarInitName(expr.Sel.Name) + "(), " + value + ")"
7455
+ }
7456
+ }
7457
+ if obj != nil && packageVarReadNeedsPointerValue(obj.Type()) {
7458
+ value = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
7459
+ "<" + o.tsNonNilTypeFor(ctx, obj.Type()) + ">(" + value + ")"
7460
+ }
7461
+ return value, nil
5798
7462
  }
5799
7463
  }
5800
7464
  }
5801
7465
  if selection := ctx.semPkg.source.TypesInfo.Selections[expr]; selection != nil {
5802
7466
  switch selection.Kind() {
5803
7467
  case types.MethodVal:
5804
- if receiver := receiverNamedType(selection.Recv()); namedNonInterfaceNonStructType(receiver) {
7468
+ namedReceiver := methodReceiverNamedType(selection.Obj())
7469
+ if namedReceiver == nil {
7470
+ namedReceiver = selectedReceiverNamedType(ctx.semPkg.source, expr, selection)
7471
+ }
7472
+ if namedNonInterfaceNonStructType(namedReceiver) {
5805
7473
  receiverExpr, diagnostics := o.lowerNamedReceiverForMethod(ctx, expr.X, selection)
5806
- methodExpr := o.methodFunctionExpr(ctx, receiver, selection.Obj(), expr.Sel.Name)
7474
+ methodExpr := o.methodFunctionExpr(ctx, namedReceiver, selection.Obj(), expr.Sel.Name)
5807
7475
  return o.lowerMethodValueClosure(ctx, selection, receiverExpr, methodExpr, true), diagnostics
5808
7476
  }
5809
7477
  receiver, diagnostics := o.lowerMethodReceiverExpr(ctx, expr.X, selection)
@@ -5818,9 +7486,41 @@ func (o *LoweringOwner) lowerSelectorExpr(ctx lowerFileContext, expr *ast.Select
5818
7486
  }
5819
7487
  }
5820
7488
  left, diagnostics := o.lowerExpr(ctx, expr.X)
7489
+ left = parenthesizeAwaitedExpr(left)
5821
7490
  return left + "." + expr.Sel.Name, diagnostics
5822
7491
  }
5823
7492
 
7493
+ func packageVarSelectorNeedsPointerValue(ctx lowerFileContext, expr ast.Expr) bool {
7494
+ selector, ok := ast.Unparen(expr).(*ast.SelectorExpr)
7495
+ if !ok || ctx.semPkg == nil || ctx.semPkg.source == nil {
7496
+ return false
7497
+ }
7498
+ if selection := ctx.semPkg.source.TypesInfo.Selections[selector]; selection != nil {
7499
+ return false
7500
+ }
7501
+ ident, ok := ast.Unparen(selector.X).(*ast.Ident)
7502
+ if !ok {
7503
+ return false
7504
+ }
7505
+ pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName)
7506
+ if importAliasForPkgName(ctx, pkgName) == "" {
7507
+ return false
7508
+ }
7509
+ obj, _ := ctx.semPkg.source.TypesInfo.Uses[selector.Sel].(*types.Var)
7510
+ return obj != nil && packageVarReadNeedsPointerValue(obj.Type())
7511
+ }
7512
+
7513
+ func packageVarReadNeedsPointerValue(typ types.Type) bool {
7514
+ if typ == nil || isPointerType(typ) {
7515
+ return false
7516
+ }
7517
+ if isStructValueType(typ) {
7518
+ return true
7519
+ }
7520
+ _, ok := types.Unalias(typ).Underlying().(*types.Array)
7521
+ return ok
7522
+ }
7523
+
5824
7524
  func (o *LoweringOwner) packageVarSetterForAssignment(ctx lowerFileContext, expr ast.Expr) (string, bool) {
5825
7525
  if ident, ok := unwrapParenExpr(expr).(*ast.Ident); ok {
5826
7526
  obj, _ := objectForIdent(ctx, ident).(*types.Var)
@@ -5828,10 +7528,13 @@ func (o *LoweringOwner) packageVarSetterForAssignment(ctx lowerFileContext, expr
5828
7528
  return "", false
5829
7529
  }
5830
7530
  alias := ctx.localAliases[obj]
5831
- if alias == "" {
5832
- return "", false
7531
+ if alias != "" {
7532
+ return alias + "." + packageVarSetterName(ident.Name), true
7533
+ }
7534
+ if ctx.lazyPackageVars[obj] {
7535
+ return packageVarSetterName(ident.Name), true
5833
7536
  }
5834
- return alias + "." + packageVarSetterName(ident.Name), true
7537
+ return "", false
5835
7538
  }
5836
7539
  selector, ok := unwrapParenExpr(expr).(*ast.SelectorExpr)
5837
7540
  if !ok {
@@ -5845,7 +7548,7 @@ func (o *LoweringOwner) packageVarSetterForAssignment(ctx lowerFileContext, expr
5845
7548
  if pkgName == nil {
5846
7549
  return "", false
5847
7550
  }
5848
- alias := ctx.importNames[pkgName.Name()]
7551
+ alias := importAliasForPkgName(ctx, pkgName)
5849
7552
  if alias == "" {
5850
7553
  return "", false
5851
7554
  }
@@ -5856,6 +7559,36 @@ func (o *LoweringOwner) packageVarSetterForAssignment(ctx lowerFileContext, expr
5856
7559
  return alias + "." + packageVarSetterName(selector.Sel.Name), true
5857
7560
  }
5858
7561
 
7562
+ func (o *LoweringOwner) packageVarAssignmentValue(
7563
+ ctx lowerFileContext,
7564
+ lhs ast.Expr,
7565
+ targetType types.Type,
7566
+ right string,
7567
+ tok token.Token,
7568
+ ) (string, bool) {
7569
+ if tok == token.ASSIGN {
7570
+ return right, true
7571
+ }
7572
+ left, diagnostics := o.lowerExpr(ctx, lhs)
7573
+ if len(diagnostics) != 0 {
7574
+ return "", false
7575
+ }
7576
+ if tok == token.AND_NOT_ASSIGN {
7577
+ return left + " & ~(" + right + ")", true
7578
+ }
7579
+ if helper, ok := wideIntegerAssignHelper(targetType, tok); ok {
7580
+ return o.runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")", true
7581
+ }
7582
+ if value, ok := integerQuotientAssignValueExpr(targetType, left, right, tok); ok {
7583
+ return value, true
7584
+ }
7585
+ op := tok.String()
7586
+ if before, ok := strings.CutSuffix(op, "="); ok {
7587
+ op = before
7588
+ }
7589
+ return left + " " + op + " " + right, true
7590
+ }
7591
+
5859
7592
  func (o *LoweringOwner) tsPackageVarSetterValueTypeFor(ctx lowerFileContext, typ types.Type) string {
5860
7593
  if signature := unnamedSignatureForType(typ); signature != nil {
5861
7594
  return o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
@@ -5870,25 +7603,28 @@ func (o *LoweringOwner) lowerFieldSelectionExpr(
5870
7603
  address bool,
5871
7604
  ) (string, []Diagnostic) {
5872
7605
  receiver, diagnostics := o.lowerFieldReceiverExpr(ctx, expr.X)
7606
+ receiver = parenthesizeAwaitedExpr(receiver)
5873
7607
  index := selection.Index()
5874
7608
  if len(index) == 0 {
7609
+ fieldName := tsStructFieldName(expr.Sel.Name, 0)
5875
7610
  if address {
5876
- return o.lowerFieldAddressExpr(ctx, receiver, ctx.semPkg.source.TypesInfo.TypeOf(expr.X), expr.Sel.Name), diagnostics
7611
+ return o.lowerFieldAddressExpr(ctx, receiver, ctx.semPkg.source.TypesInfo.TypeOf(expr.X), fieldName), diagnostics
5877
7612
  }
5878
- return receiver + "." + expr.Sel.Name, diagnostics
7613
+ return receiver + "." + fieldName, diagnostics
5879
7614
  }
5880
7615
 
5881
7616
  typ := derefPointerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
5882
7617
  for idx, fieldIndex := range index {
5883
7618
  structType := structUnderlyingType(typ)
5884
7619
  if structType == nil || fieldIndex < 0 || fieldIndex >= structType.NumFields() {
7620
+ fieldName := tsStructFieldName(expr.Sel.Name, 0)
5885
7621
  if address {
5886
- return receiver + "._fields." + expr.Sel.Name, diagnostics
7622
+ return receiver + "._fields." + fieldName, diagnostics
5887
7623
  }
5888
- return receiver + "." + expr.Sel.Name, diagnostics
7624
+ return receiver + "." + fieldName, diagnostics
5889
7625
  }
5890
7626
  field := structType.Field(fieldIndex)
5891
- name := field.Name()
7627
+ name := tsStructFieldName(field.Name(), fieldIndex)
5892
7628
  if idx == len(index)-1 {
5893
7629
  if address {
5894
7630
  return o.lowerFieldAddressExpr(ctx, receiver, typ, name), diagnostics
@@ -5906,9 +7642,9 @@ func (o *LoweringOwner) lowerFieldSelectionExpr(
5906
7642
  }
5907
7643
 
5908
7644
  if address {
5909
- return o.lowerFieldAddressExpr(ctx, receiver, typ, expr.Sel.Name), diagnostics
7645
+ return o.lowerFieldAddressExpr(ctx, receiver, typ, tsStructFieldName(expr.Sel.Name, 0)), diagnostics
5910
7646
  }
5911
- return receiver + "." + expr.Sel.Name, diagnostics
7647
+ return receiver + "." + tsStructFieldName(expr.Sel.Name, 0), diagnostics
5912
7648
  }
5913
7649
 
5914
7650
  func (o *LoweringOwner) lowerFieldAddressExpr(ctx lowerFileContext, receiver string, typ types.Type, fieldName string) string {
@@ -5980,9 +7716,11 @@ func (o *LoweringOwner) lowerFieldReceiverExpr(ctx lowerFileContext, expr ast.Ex
5980
7716
  return o.lowerPointerValueExpr(ctx, expr)
5981
7717
  }
5982
7718
  value, diagnostics := o.lowerExpr(ctx, expr)
7719
+ value = parenthesizeAwaitedExpr(value)
5983
7720
  if obj := objectForValueExpr(ctx, expr); obj != nil &&
5984
- ctx.model.needsVarRef[obj] &&
7721
+ objectNeedsVarRef(ctx, obj) &&
5985
7722
  isStructValueType(obj.Type()) &&
7723
+ !packageVarSelectorNeedsPointerValue(ctx, expr) &&
5986
7724
  fieldReceiverNeedsVarRefValue(ctx, expr, obj) {
5987
7725
  return value + ".value", diagnostics
5988
7726
  }
@@ -5993,7 +7731,16 @@ func fieldReceiverNeedsVarRefValue(ctx lowerFileContext, expr ast.Expr, obj type
5993
7731
  if _, ok := expr.(*ast.Ident); !ok {
5994
7732
  return true
5995
7733
  }
5996
- return ctx.localAliases[obj] != "" || ctx.identAliases[obj] != ""
7734
+ if ctx.identAliases[obj] != "" {
7735
+ return !ctx.identAliasRefs[obj]
7736
+ }
7737
+ if ctx.localAliases[obj] != "" {
7738
+ if varObj, ok := obj.(*types.Var); ok && packageVarReadNeedsPointerValue(varObj.Type()) {
7739
+ return false
7740
+ }
7741
+ return !ctx.lazyPackageVars[obj]
7742
+ }
7743
+ return false
5997
7744
  }
5998
7745
 
5999
7746
  func (o *LoweringOwner) lowerMethodReceiverExpr(
@@ -6016,14 +7763,24 @@ func (o *LoweringOwner) lowerMethodReceiverExpr(
6016
7763
  receiver, diagnostics = o.lowerPointerValueExpr(ctx, expr)
6017
7764
  } else {
6018
7765
  receiver, diagnostics = o.lowerExpr(ctx, expr)
7766
+ receiver = parenthesizeAwaitedExpr(receiver)
6019
7767
  }
6020
7768
  receiverType := ctx.semPkg.source.TypesInfo.TypeOf(expr)
7769
+ if !receiverPointer {
7770
+ if obj := objectForValueExpr(ctx, expr); obj != nil &&
7771
+ objectNeedsVarRef(ctx, obj) &&
7772
+ isStructValueType(obj.Type()) &&
7773
+ !packageVarSelectorNeedsPointerValue(ctx, expr) &&
7774
+ fieldReceiverNeedsVarRefValue(ctx, expr, obj) {
7775
+ receiver += ".value"
7776
+ }
7777
+ }
6021
7778
  if index := selection.Index(); len(index) > 1 && !o.receiverUsesOverridePackage(receiverType) {
6022
7779
  receiver, receiverType = o.lowerPromotedMethodReceiver(ctx, receiver, receiverType, index[:len(index)-1])
6023
7780
  }
6024
7781
  if receiverPointer {
6025
7782
  if obj := objectForValueExpr(ctx, expr); obj != nil &&
6026
- ctx.model.needsVarRef[obj] &&
7783
+ objectNeedsVarRef(ctx, obj) &&
6027
7784
  isStructValueType(obj.Type()) &&
6028
7785
  fieldReceiverNeedsVarRefValue(ctx, expr, obj) {
6029
7786
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
@@ -6074,16 +7831,38 @@ func (o *LoweringOwner) lowerPromotedMethodReceiver(
6074
7831
  return receiver, typ
6075
7832
  }
6076
7833
 
7834
+ func promotedMethodReceiverType(typ types.Type, index []int) types.Type {
7835
+ typ = derefPointerType(typ)
7836
+ for _, fieldIndex := range index {
7837
+ structType := structUnderlyingType(typ)
7838
+ if structType == nil || fieldIndex < 0 || fieldIndex >= structType.NumFields() {
7839
+ return typ
7840
+ }
7841
+ typ = structType.Field(fieldIndex).Type()
7842
+ if pointer, ok := types.Unalias(typ).Underlying().(*types.Pointer); ok {
7843
+ typ = pointer.Elem()
7844
+ }
7845
+ }
7846
+ return typ
7847
+ }
7848
+
6077
7849
  func (o *LoweringOwner) lowerAssignmentTarget(
6078
7850
  ctx lowerFileContext,
6079
7851
  expr ast.Expr,
6080
7852
  declare bool,
6081
7853
  ) (string, []Diagnostic) {
6082
- switch typed := expr.(type) {
7854
+ switch typed := unwrapParenExpr(expr).(type) {
6083
7855
  case *ast.Ident:
6084
7856
  if declare {
6085
7857
  return o.lowerIdent(ctx, typed, true), nil
6086
7858
  }
7859
+ if obj := objectForIdent(ctx, typed); obj != nil && ctx.lazyPackageVars[obj] {
7860
+ target := o.lowerIdent(ctx, typed, true)
7861
+ if ctx.model.needsVarRef[obj] {
7862
+ target += ".value"
7863
+ }
7864
+ return target, nil
7865
+ }
6087
7866
  return o.lowerIdent(ctx, typed, false), nil
6088
7867
  case *ast.StarExpr:
6089
7868
  return o.lowerPointerValueExpr(ctx, typed.X)
@@ -6093,7 +7872,10 @@ func (o *LoweringOwner) lowerAssignmentTarget(
6093
7872
  }
6094
7873
 
6095
7874
  func (o *LoweringOwner) lowerAddressExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
6096
- switch typed := expr.(type) {
7875
+ if value, ok := o.lowerPackageVarAddressExpr(ctx, expr); ok {
7876
+ return value, nil
7877
+ }
7878
+ switch typed := unwrapParenExpr(expr).(type) {
6097
7879
  case *ast.Ident:
6098
7880
  return o.lowerIdent(ctx, typed, true), nil
6099
7881
  case *ast.CompositeLit:
@@ -6115,6 +7897,55 @@ func (o *LoweringOwner) lowerAddressExpr(ctx lowerFileContext, expr ast.Expr) (s
6115
7897
  }
6116
7898
  }
6117
7899
 
7900
+ func (o *LoweringOwner) lowerPackageVarAddressExpr(ctx lowerFileContext, expr ast.Expr) (string, bool) {
7901
+ switch typed := unwrapParenExpr(expr).(type) {
7902
+ case *ast.Ident:
7903
+ obj, _ := objectForIdent(ctx, typed).(*types.Var)
7904
+ if obj == nil || !objectNeedsVarRef(ctx, obj) {
7905
+ return "", false
7906
+ }
7907
+ return o.lowerIdent(ctx, typed, true), true
7908
+ case *ast.SelectorExpr:
7909
+ if selection := ctx.semPkg.source.TypesInfo.Selections[typed]; selection != nil {
7910
+ return "", false
7911
+ }
7912
+ ident, ok := unwrapParenExpr(typed.X).(*ast.Ident)
7913
+ if !ok {
7914
+ return "", false
7915
+ }
7916
+ pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName)
7917
+ if pkgName == nil {
7918
+ return "", false
7919
+ }
7920
+ alias := importAliasForPkgName(ctx, pkgName)
7921
+ if alias == "" {
7922
+ return "", false
7923
+ }
7924
+ obj, _ := ctx.semPkg.source.TypesInfo.Uses[typed.Sel].(*types.Var)
7925
+ if obj == nil || !objectNeedsVarRef(ctx, obj) {
7926
+ return "", false
7927
+ }
7928
+ return alias + "." + typed.Sel.Name, true
7929
+ default:
7930
+ return "", false
7931
+ }
7932
+ }
7933
+
7934
+ func importAliasForPkgName(ctx lowerFileContext, pkgName *types.PkgName) string {
7935
+ if pkgName == nil {
7936
+ return ""
7937
+ }
7938
+ if alias := ctx.importObjects[pkgName]; alias != "" {
7939
+ return alias
7940
+ }
7941
+ if imported := pkgName.Imported(); imported != nil {
7942
+ if alias := ctx.importPaths[imported.Path()]; alias != "" {
7943
+ return alias
7944
+ }
7945
+ }
7946
+ return ctx.importNames[pkgName.Name()]
7947
+ }
7948
+
6118
7949
  func (o *LoweringOwner) lowerIndexAddressExpr(ctx lowerFileContext, expr *ast.IndexExpr) (string, []Diagnostic) {
6119
7950
  target, targetDiagnostics := o.lowerExpr(ctx, expr.X)
6120
7951
  index, indexDiagnostics := o.lowerExpr(ctx, expr.Index)
@@ -6171,46 +8002,240 @@ func (o *LoweringOwner) lowerIndexAddressIntegerExpr(
6171
8002
  if isStringType(targetType) || isMapType(targetType) {
6172
8003
  return "", diagnostics, false
6173
8004
  }
6174
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperIndexAddress) +
6175
- "(" + o.lowerIndexTarget(ctx, target, targetType) + ", " + index + ")", diagnostics, true
8005
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperIndexAddress) +
8006
+ "(" + o.lowerIndexTarget(ctx, target, targetType) + ", " + index + ")", diagnostics, true
8007
+ }
8008
+
8009
+ func (o *LoweringOwner) lowerPointerValueExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
8010
+ if value, diagnostics, ok := o.lowerUnsafeStringPointerValue(ctx, expr); ok {
8011
+ return value, diagnostics
8012
+ }
8013
+ if value, diagnostics, ok := o.lowerUnsafeStringByteSlicePointerValue(ctx, expr); ok {
8014
+ return value, diagnostics
8015
+ }
8016
+ base, diagnostics := o.lowerExpr(ctx, expr)
8017
+ typeArg := ""
8018
+ if pointer, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(expr)).Underlying().(*types.Pointer); ok {
8019
+ typeArg = "<" + o.tsTypeFor(ctx, pointer.Elem()) + ">"
8020
+ }
8021
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + typeArg + "(" + base + ")", diagnostics
8022
+ }
8023
+
8024
+ func (o *LoweringOwner) lowerUnsafeStringPointerValue(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic, bool) {
8025
+ call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
8026
+ if !ok || len(call.Args) != 1 {
8027
+ return "", nil, false
8028
+ }
8029
+ targetType := typeFromExpr(ctx, call.Fun)
8030
+ if targetType == nil {
8031
+ return "", nil, false
8032
+ }
8033
+ targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
8034
+ if targetPointer == nil || !isStringType(targetPointer.Elem()) {
8035
+ return "", nil, false
8036
+ }
8037
+ unsafeCall, ok := unwrapParenExpr(call.Args[0]).(*ast.CallExpr)
8038
+ unsafeTargetType := typeFromExpr(ctx, unsafeCall.Fun)
8039
+ if !ok || len(unsafeCall.Args) != 1 || unsafeTargetType == nil || !isUnsafePointerType(unsafeTargetType) {
8040
+ return "", nil, false
8041
+ }
8042
+ address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
8043
+ if !ok || address.Op != token.AND || !isByteSliceType(ctx.semPkg.source.TypesInfo.TypeOf(address.X)) {
8044
+ return "", nil, false
8045
+ }
8046
+ value, diagnostics := o.lowerExpr(ctx, address.X)
8047
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperBytesToString) + "(" + value + ")", diagnostics, true
8048
+ }
8049
+
8050
+ func (o *LoweringOwner) lowerUnsafeStringByteSlicePointerValue(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic, bool) {
8051
+ call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
8052
+ if !ok || len(call.Args) != 1 {
8053
+ return "", nil, false
8054
+ }
8055
+ targetType := typeFromExpr(ctx, call.Fun)
8056
+ if targetType == nil {
8057
+ return "", nil, false
8058
+ }
8059
+ targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
8060
+ if targetPointer == nil || !isByteSliceType(targetPointer.Elem()) {
8061
+ return "", nil, false
8062
+ }
8063
+ unsafeCall, ok := unwrapParenExpr(call.Args[0]).(*ast.CallExpr)
8064
+ unsafeTargetType := typeFromExpr(ctx, unsafeCall.Fun)
8065
+ if !ok || len(unsafeCall.Args) != 1 || unsafeTargetType == nil || !isUnsafePointerType(unsafeTargetType) {
8066
+ return "", nil, false
8067
+ }
8068
+ address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
8069
+ if !ok || address.Op != token.AND {
8070
+ return "", nil, false
8071
+ }
8072
+ source, ok := localStringSliceHeaderSource(ctx, address.X)
8073
+ if !ok {
8074
+ return "", nil, false
8075
+ }
8076
+ value, diagnostics := o.lowerExpr(ctx, source)
8077
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperStringToBytes) + "(" + value + ")", diagnostics, true
8078
+ }
8079
+
8080
+ func (o *LoweringOwner) lowerReflectHeaderPointerConversion(
8081
+ ctx lowerFileContext,
8082
+ targetType types.Type,
8083
+ expr ast.Expr,
8084
+ ) (string, []Diagnostic, bool) {
8085
+ targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
8086
+ if targetPointer == nil {
8087
+ return "", nil, false
8088
+ }
8089
+ header, _ := types.Unalias(targetPointer.Elem()).(*types.Named)
8090
+ if header == nil || header.Obj() == nil || header.Obj().Pkg() == nil || header.Obj().Pkg().Path() != "reflect" {
8091
+ return "", nil, false
8092
+ }
8093
+ unsafeCall, ok := unwrapParenExpr(expr).(*ast.CallExpr)
8094
+ if !ok || len(unsafeCall.Args) != 1 || !isUnsafePointerType(typeFromExpr(ctx, unsafeCall.Fun)) {
8095
+ return "", nil, false
8096
+ }
8097
+ address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
8098
+ if !ok || address.Op != token.AND {
8099
+ return "", nil, false
8100
+ }
8101
+ switch header.Obj().Name() {
8102
+ case "StringHeader":
8103
+ if !isStringType(ctx.semPkg.source.TypesInfo.TypeOf(address.X)) {
8104
+ return "", nil, false
8105
+ }
8106
+ value, diagnostics := o.lowerAddressedValueRef(ctx, address.X)
8107
+ helper := o.runtimeOwner.QualifiedHelper(RuntimeHelperStringHeaderRef) + "(" + value + ")"
8108
+ return "(" + helper + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics, true
8109
+ case "SliceHeader":
8110
+ if !isByteSliceType(ctx.semPkg.source.TypesInfo.TypeOf(address.X)) {
8111
+ return "", nil, false
8112
+ }
8113
+ value, diagnostics := o.lowerAddressedValueRef(ctx, address.X)
8114
+ helper := o.runtimeOwner.QualifiedHelper(RuntimeHelperSliceHeaderRef) + "(" + value + ")"
8115
+ return "(" + helper + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics, true
8116
+ default:
8117
+ return "", nil, false
8118
+ }
8119
+ }
8120
+
8121
+ func (o *LoweringOwner) lowerUnsafeArrayPointerConversion(
8122
+ ctx lowerFileContext,
8123
+ targetType types.Type,
8124
+ expr ast.Expr,
8125
+ ) (string, []Diagnostic, bool) {
8126
+ targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
8127
+ if targetPointer == nil {
8128
+ return "", nil, false
8129
+ }
8130
+ array, _ := types.Unalias(targetPointer.Elem()).Underlying().(*types.Array)
8131
+ if array == nil {
8132
+ return "", nil, false
8133
+ }
8134
+ unsafeCall, ok := unwrapParenExpr(expr).(*ast.CallExpr)
8135
+ if !ok || len(unsafeCall.Args) != 1 || !isUnsafePointerType(typeFromExpr(ctx, unsafeCall.Fun)) {
8136
+ return "", nil, false
8137
+ }
8138
+ address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
8139
+ if !ok || address.Op != token.AND {
8140
+ return "", nil, false
8141
+ }
8142
+ index, ok := unwrapParenExpr(address.X).(*ast.IndexExpr)
8143
+ if !ok {
8144
+ return "", nil, false
8145
+ }
8146
+ ref, diagnostics := o.lowerAddressExpr(ctx, index)
8147
+ helper := o.runtimeOwner.QualifiedHelper(RuntimeHelperArrayPointerFromIndexRef) +
8148
+ "<" + o.tsTypeFor(ctx, array.Elem()) + ">(" + ref + ", " + strconv.FormatInt(array.Len(), 10) + ")"
8149
+ return "(" + helper + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics, true
8150
+ }
8151
+
8152
+ func (o *LoweringOwner) lowerAddressedValueRef(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
8153
+ if ident, ok := unwrapParenExpr(expr).(*ast.Ident); ok {
8154
+ if obj := objectForIdent(ctx, ident); obj != nil && ctx.model.needsVarRef[obj] {
8155
+ return o.lowerIdent(ctx, ident, true), nil
8156
+ }
8157
+ }
8158
+ value, diagnostics := o.lowerExpr(ctx, expr)
8159
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(" + value + ")", diagnostics
6176
8160
  }
6177
8161
 
6178
- func (o *LoweringOwner) lowerPointerValueExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
6179
- if value, diagnostics, ok := o.lowerUnsafeStringPointerValue(ctx, expr); ok {
6180
- return value, diagnostics
8162
+ func localStringSliceHeaderSource(ctx lowerFileContext, expr ast.Expr) (ast.Expr, bool) {
8163
+ lit, ok := unwrapParenExpr(expr).(*ast.CompositeLit)
8164
+ if !ok {
8165
+ return nil, false
6181
8166
  }
6182
- base, diagnostics := o.lowerExpr(ctx, expr)
6183
- typeArg := ""
6184
- if pointer, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(expr)).Underlying().(*types.Pointer); ok {
6185
- typeArg = "<" + o.tsTypeFor(ctx, pointer.Elem()) + ">"
8167
+ structType, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(lit)).Underlying().(*types.Struct)
8168
+ if !ok || structType.NumFields() != 2 {
8169
+ return nil, false
6186
8170
  }
6187
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + typeArg + "(" + base + ")", diagnostics
8171
+ if !isStringType(structType.Field(0).Type()) || !isIntegerType(structType.Field(1).Type()) {
8172
+ return nil, false
8173
+ }
8174
+ var source ast.Expr
8175
+ var capacity ast.Expr
8176
+ for idx, elt := range lit.Elts {
8177
+ fieldIndex := idx
8178
+ valueExpr := elt
8179
+ if keyed, ok := elt.(*ast.KeyValueExpr); ok {
8180
+ valueExpr = keyed.Value
8181
+ ident, ok := keyed.Key.(*ast.Ident)
8182
+ if !ok {
8183
+ return nil, false
8184
+ }
8185
+ fieldIndex = -1
8186
+ for index := range structType.NumFields() {
8187
+ if structType.Field(index).Name() == ident.Name {
8188
+ fieldIndex = index
8189
+ break
8190
+ }
8191
+ }
8192
+ if fieldIndex < 0 {
8193
+ return nil, false
8194
+ }
8195
+ }
8196
+ switch fieldIndex {
8197
+ case 0:
8198
+ source = valueExpr
8199
+ case 1:
8200
+ capacity = valueExpr
8201
+ }
8202
+ }
8203
+ if source == nil || capacity == nil {
8204
+ return nil, false
8205
+ }
8206
+ if !isStringType(ctx.semPkg.source.TypesInfo.TypeOf(source)) ||
8207
+ !isIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(capacity)) {
8208
+ return nil, false
8209
+ }
8210
+ if !isLenCallOfExpr(ctx, capacity, source) {
8211
+ return nil, false
8212
+ }
8213
+ return source, true
6188
8214
  }
6189
8215
 
6190
- func (o *LoweringOwner) lowerUnsafeStringPointerValue(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic, bool) {
8216
+ func isLenCallOfExpr(ctx lowerFileContext, expr ast.Expr, target ast.Expr) bool {
6191
8217
  call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
6192
8218
  if !ok || len(call.Args) != 1 {
6193
- return "", nil, false
6194
- }
6195
- targetType := typeFromExpr(ctx, call.Fun)
6196
- if targetType == nil {
6197
- return "", nil, false
8219
+ return false
6198
8220
  }
6199
- targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
6200
- if targetPointer == nil || !isStringType(targetPointer.Elem()) {
6201
- return "", nil, false
8221
+ ident, ok := unwrapParenExpr(call.Fun).(*ast.Ident)
8222
+ if !ok || ident.Name != "len" {
8223
+ return false
6202
8224
  }
6203
- unsafeCall, ok := unwrapParenExpr(call.Args[0]).(*ast.CallExpr)
6204
- unsafeTargetType := typeFromExpr(ctx, unsafeCall.Fun)
6205
- if !ok || len(unsafeCall.Args) != 1 || unsafeTargetType == nil || !isUnsafePointerType(unsafeTargetType) {
6206
- return "", nil, false
8225
+ if objectForIdent(ctx, ident) != types.Universe.Lookup("len") {
8226
+ return false
6207
8227
  }
6208
- address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
6209
- if !ok || address.Op != token.AND || !isByteSliceType(ctx.semPkg.source.TypesInfo.TypeOf(address.X)) {
6210
- return "", nil, false
8228
+ return sameLoweredSourceExpr(ctx, call.Args[0], target)
8229
+ }
8230
+
8231
+ func sameLoweredSourceExpr(ctx lowerFileContext, left ast.Expr, right ast.Expr) bool {
8232
+ left = unwrapParenExpr(left)
8233
+ right = unwrapParenExpr(right)
8234
+ if leftIdent, ok := left.(*ast.Ident); ok {
8235
+ rightIdent, ok := right.(*ast.Ident)
8236
+ return ok && objectForIdent(ctx, leftIdent) == objectForIdent(ctx, rightIdent)
6211
8237
  }
6212
- value, diagnostics := o.lowerExpr(ctx, address.X)
6213
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperBytesToString) + "(" + value + ")", diagnostics, true
8238
+ return false
6214
8239
  }
6215
8240
 
6216
8241
  func (o *LoweringOwner) lowerPointerStorageExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
@@ -6362,6 +8387,13 @@ func (o *LoweringOwner) lowerCompositeLit(
6362
8387
  lit *ast.CompositeLit,
6363
8388
  markStruct bool,
6364
8389
  ) (string, []Diagnostic) {
8390
+ if len(lit.Elts) == 0 {
8391
+ if typeParam, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(lit)).(*types.TypeParam); ok {
8392
+ if typeParamInScope(ctx, typeParam) {
8393
+ return o.lowerDeclarationZeroValueExpr(ctx, typeParam), nil
8394
+ }
8395
+ }
8396
+ }
6365
8397
  named := namedStructType(ctx.semPkg.source.TypesInfo.TypeOf(lit))
6366
8398
  if named != nil {
6367
8399
  return o.lowerStructCompositeLit(ctx, lit, named, markStruct)
@@ -6402,6 +8434,7 @@ func (o *LoweringOwner) lowerStructCompositeLit(
6402
8434
  ) (string, []Diagnostic) {
6403
8435
  structType, _ := named.Underlying().(*types.Struct)
6404
8436
  fields := make([]string, 0, len(lit.Elts))
8437
+ var prelude []string
6405
8438
  var diagnostics []Diagnostic
6406
8439
  for idx, elt := range lit.Elts {
6407
8440
  fieldName := ""
@@ -6410,9 +8443,13 @@ func (o *LoweringOwner) lowerStructCompositeLit(
6410
8443
  if keyed, ok := elt.(*ast.KeyValueExpr); ok {
6411
8444
  valueExpr = keyed.Value
6412
8445
  if ident, ok := keyed.Key.(*ast.Ident); ok {
6413
- fieldName = ident.Name
6414
- if field := fieldByName(structType, fieldName); field != nil {
6415
- fieldType = field.Type()
8446
+ for index := range structType.NumFields() {
8447
+ field := structType.Field(index)
8448
+ if field.Name() == ident.Name {
8449
+ fieldName = tsStructFieldName(field.Name(), index)
8450
+ fieldType = field.Type()
8451
+ break
8452
+ }
6416
8453
  }
6417
8454
  }
6418
8455
  } else if idx < structType.NumFields() {
@@ -6427,6 +8464,11 @@ func (o *LoweringOwner) lowerStructCompositeLit(
6427
8464
  value, valueDiagnostics := o.lowerExpr(ctx, valueExpr)
6428
8465
  diagnostics = append(diagnostics, valueDiagnostics...)
6429
8466
  value = o.lowerValueForTarget(ctx, valueExpr, fieldType, value)
8467
+ if compositeLiteralFieldNeedsPreEval(ctx, valueExpr) {
8468
+ temp := ctx.tempName("LiteralField")
8469
+ prelude = append(prelude, "const "+temp+" = "+value)
8470
+ value = temp
8471
+ }
6430
8472
  fields = append(fields, fieldName+": "+value)
6431
8473
  }
6432
8474
 
@@ -6437,9 +8479,30 @@ func (o *LoweringOwner) lowerStructCompositeLit(
6437
8479
  if markStruct {
6438
8480
  expr = o.runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue) + "(" + expr + ")"
6439
8481
  }
8482
+ if len(prelude) != 0 {
8483
+ body := strings.Join(prelude, "; ") + "; return " + expr
8484
+ if strings.Contains(body, "await ") {
8485
+ return "(await (async () => { " + body + " })())", diagnostics
8486
+ }
8487
+ return "(() => { " + body + " })()", diagnostics
8488
+ }
6440
8489
  return expr, diagnostics
6441
8490
  }
6442
8491
 
8492
+ func compositeLiteralFieldNeedsPreEval(ctx lowerFileContext, expr ast.Expr) bool {
8493
+ switch typed := unwrapParenExpr(expr).(type) {
8494
+ case *ast.CallExpr:
8495
+ if ident, ok := typed.Fun.(*ast.Ident); ok && isBuiltinCallTarget(ctx, ident) {
8496
+ return false
8497
+ }
8498
+ return typeFromExpr(ctx, typed.Fun) == nil
8499
+ case *ast.UnaryExpr:
8500
+ return typed.Op == token.ARROW
8501
+ default:
8502
+ return false
8503
+ }
8504
+ }
8505
+
6443
8506
  func (o *LoweringOwner) lowerAnonymousStructCompositeLit(
6444
8507
  ctx lowerFileContext,
6445
8508
  lit *ast.CompositeLit,
@@ -6460,10 +8523,10 @@ func (o *LoweringOwner) lowerAnonymousStructCompositeLit(
6460
8523
  if keyed, ok := elt.(*ast.KeyValueExpr); ok {
6461
8524
  valueExpr = keyed.Value
6462
8525
  if ident, ok := keyed.Key.(*ast.Ident); ok {
6463
- fieldName = ident.Name
6464
8526
  for index := range structType.NumFields() {
6465
8527
  field := structType.Field(index)
6466
- if field.Name() == fieldName {
8528
+ if field.Name() == ident.Name {
8529
+ fieldName = tsStructFieldName(field.Name(), index)
6467
8530
  fieldIndex = index
6468
8531
  fieldType = field.Type()
6469
8532
  break
@@ -6571,7 +8634,7 @@ func (o *LoweringOwner) lowerSliceCompositeLit(
6571
8634
  nextIndex = index + 1
6572
8635
  }
6573
8636
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperArrayToSlice) +
6574
- "<" + o.tsTypeFor(ctx, slice.Elem()) + ">([" + strings.Join(values, ", ") + "])", diagnostics
8637
+ "<" + o.tsSliceElemTypeFor(ctx, slice.Elem()) + ">([" + strings.Join(values, ", ") + "])", diagnostics
6575
8638
  }
6576
8639
 
6577
8640
  func (o *LoweringOwner) lowerMapCompositeLit(
@@ -6602,7 +8665,7 @@ func (o *LoweringOwner) lowerTypeAssertExpr(ctx lowerFileContext, expr *ast.Type
6602
8665
  targetType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Type)
6603
8666
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperMustTypeAssert) +
6604
8667
  "<" + o.tsTypeAssertionTypeFor(ctx, targetType) + ">(" +
6605
- value + ", " + o.runtimeTypeInfoExpr(targetType) + ")", diagnostics
8668
+ value + ", " + o.runtimeTypeAssertInfoExpr(ctx, targetType) + ")", diagnostics
6606
8669
  }
6607
8670
 
6608
8671
  func (o *LoweringOwner) lowerTupleExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
@@ -6612,7 +8675,7 @@ func (o *LoweringOwner) lowerTupleExpr(ctx lowerFileContext, expr ast.Expr) (str
6612
8675
  targetType := ctx.semPkg.source.TypesInfo.TypeOf(typed.Type)
6613
8676
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperTypeAssertTuple) +
6614
8677
  "<" + o.tsTypeAssertionTypeFor(ctx, targetType) + ">(" +
6615
- value + ", " + o.runtimeTypeInfoExpr(targetType) + ")", diagnostics
8678
+ value + ", " + o.runtimeTypeAssertInfoExpr(ctx, targetType) + ")", diagnostics
6616
8679
  case *ast.IndexExpr:
6617
8680
  if isMapType(ctx.semPkg.source.TypesInfo.TypeOf(typed.X)) {
6618
8681
  target, targetDiagnostics := o.lowerExpr(ctx, typed.X)
@@ -6644,6 +8707,9 @@ func (o *LoweringOwner) lowerValueForTarget(
6644
8707
  ) string {
6645
8708
  sourceType := ctx.semPkg.source.TypesInfo.TypeOf(expr)
6646
8709
  if isComplexType(targetType) {
8710
+ if isComplexType(sourceType) {
8711
+ return value
8712
+ }
6647
8713
  if isRealNumericConstantExpr(ctx, expr) {
6648
8714
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperComplex) + "(" + value + ", 0)"
6649
8715
  }
@@ -6697,6 +8763,14 @@ func isRealNumericConstantExpr(ctx lowerFileContext, expr ast.Expr) bool {
6697
8763
  }
6698
8764
  }
6699
8765
 
8766
+ func lowerPrefixUnaryExpr(op token.Token, value string) string {
8767
+ prefix := op.String()
8768
+ if (op == token.SUB && strings.HasPrefix(value, "-")) || (op == token.ADD && strings.HasPrefix(value, "+")) {
8769
+ return prefix + "(" + value + ")"
8770
+ }
8771
+ return prefix + value
8772
+ }
8773
+
6700
8774
  func (o *LoweringOwner) lowerValueForTargetTypes(
6701
8775
  ctx lowerFileContext,
6702
8776
  targetType types.Type,
@@ -6704,6 +8778,9 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
6704
8778
  value string,
6705
8779
  cloneStructValue bool,
6706
8780
  ) string {
8781
+ if targetType == nil || sourceType == nil {
8782
+ return value
8783
+ }
6707
8784
  if isFunctionType(targetType) && isUntypedNilType(sourceType) {
6708
8785
  return "(" + value + " as " + o.tsTypeFor(ctx, targetType) + ")"
6709
8786
  }
@@ -6734,6 +8811,15 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
6734
8811
  return o.lowerStructClone(value)
6735
8812
  }
6736
8813
  if isIntegerType(targetType) && isIntegerType(sourceType) {
8814
+ if isBasicFixedWideIntegerType(targetType) {
8815
+ if bits, ok := unsignedIntegerBits(targetType); ok {
8816
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
8817
+ "(" + value + ", " + strconv.Itoa(bits) + ")"
8818
+ }
8819
+ if _, ok := signedIntegerBits(targetType); ok {
8820
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperInt) + "(" + value + ")"
8821
+ }
8822
+ }
6737
8823
  if bits, ok := unsignedIntegerBits(targetType); ok && bits < 64 {
6738
8824
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
6739
8825
  "(" + value + ", " + strconv.Itoa(bits) + ")"
@@ -6751,12 +8837,28 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
6751
8837
  return value
6752
8838
  }
6753
8839
 
8840
+ func isBasicFixedWideIntegerType(typ types.Type) bool {
8841
+ basic, ok := types.Unalias(typ).(*types.Basic)
8842
+ if !ok {
8843
+ return false
8844
+ }
8845
+ switch basic.Kind() {
8846
+ case types.Int64, types.Uint64, types.Uintptr:
8847
+ return true
8848
+ default:
8849
+ return false
8850
+ }
8851
+ }
8852
+
6754
8853
  func (o *LoweringOwner) lowerNamedValueInterfaceWrapper(
6755
8854
  ctx lowerFileContext,
6756
8855
  targetType types.Type,
6757
8856
  sourceType types.Type,
6758
8857
  value string,
6759
8858
  ) string {
8859
+ if targetType == nil || sourceType == nil {
8860
+ return ""
8861
+ }
6760
8862
  if !isInterfaceType(targetType) || isInterfaceType(sourceType) {
6761
8863
  return ""
6762
8864
  }
@@ -6794,8 +8896,9 @@ func (o *LoweringOwner) lowerPrimitiveErrorWrapper(ctx lowerFileContext, sourceT
6794
8896
  if fn == nil {
6795
8897
  return ""
6796
8898
  }
6797
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperWrapPrimitiveError) +
6798
- "(" + value + ", " + o.methodFunctionExpr(ctx, named, fn, "Error") + ")"
8899
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
8900
+ "<$.GoError>(" + value + ", " + strconv.Quote(goRuntimeTypeString(sourceType)) +
8901
+ ", {\"Error\": " + o.methodFunctionExpr(ctx, named, fn, "Error") + "})"
6799
8902
  }
6800
8903
 
6801
8904
  func (o *LoweringOwner) lowerStructClone(value string) string {
@@ -6805,13 +8908,16 @@ func (o *LoweringOwner) lowerStructClone(value string) string {
6805
8908
 
6806
8909
  func (o *LoweringOwner) lowerZeroValueExpr(typ types.Type) string {
6807
8910
  if named := namedStructType(typ); named != nil && isStructValueType(typ) {
6808
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue) + "(new " + named.Obj().Name() + "())"
8911
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue) + "(new " + safeIdentifier(named.Obj().Name()) + "())"
6809
8912
  }
6810
8913
  return zeroValueExpr(typ)
6811
8914
  }
6812
8915
 
6813
8916
  func (o *LoweringOwner) lowerZeroValueExprFor(ctx lowerFileContext, typ types.Type) string {
6814
8917
  if named := namedStructType(typ); named != nil && isStructValueType(typ) {
8918
+ if crossPackageUnexportedNamedType(ctx, named) {
8919
+ return "undefined as any"
8920
+ }
6815
8921
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue) + "(new " + o.namedTypeExpr(ctx, named) + "())"
6816
8922
  }
6817
8923
  switch typed := types.Unalias(typ).Underlying().(type) {
@@ -6859,7 +8965,7 @@ func (o *LoweringOwner) lowerDeclarationZeroValueExpr(ctx lowerFileContext, typ
6859
8965
  }
6860
8966
  return value
6861
8967
  }
6862
- if !signatureHasTypeParam(ctx.signature, typeParam) {
8968
+ if !typeParamInScope(ctx, typeParam) {
6863
8969
  return zeroValueExpr(typ)
6864
8970
  }
6865
8971
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperGenericZero) +
@@ -6870,6 +8976,15 @@ func (o *LoweringOwner) runtimeTypeInfoExpr(typ types.Type) string {
6870
8976
  return o.runtimeTypeInfoExprWithSeen(typ, make(map[types.Type]bool))
6871
8977
  }
6872
8978
 
8979
+ func (o *LoweringOwner) runtimeTypeAssertInfoExpr(ctx lowerFileContext, typ types.Type) string {
8980
+ typeParam, ok := types.Unalias(typ).(*types.TypeParam)
8981
+ if !ok || !typeParamInScope(ctx, typeParam) {
8982
+ return o.runtimeTypeInfoExpr(typ)
8983
+ }
8984
+ return "__typeArgs?.[" + strconv.Quote(typeParam.Obj().Name()) + "]?.type ?? " +
8985
+ o.runtimeTypeInfoExpr(typ)
8986
+ }
8987
+
6873
8988
  func (o *LoweringOwner) runtimeTypeInfoExprWithSeen(typ types.Type, seen map[types.Type]bool) string {
6874
8989
  typeKind := o.runtimeOwner.QualifiedHelper(RuntimeHelperTypeKind)
6875
8990
  if typ == nil {
@@ -6890,20 +9005,14 @@ func (o *LoweringOwner) runtimeTypeInfoExprWithSeen(typ types.Type, seen map[typ
6890
9005
  return o.runtimeFunctionTypeInfoWithSeen(named.Underlying().(*types.Signature), runtimeNamedTypeName(named), seen)
6891
9006
  }
6892
9007
  if named := namedNonStructType(typ); named != nil {
9008
+ if basic, ok := types.Unalias(named.Underlying()).(*types.Basic); ok {
9009
+ return runtimeBasicTypeInfoExpr(typeKind, basic, runtimeNamedTypeName(named))
9010
+ }
6893
9011
  return strconv.Quote(runtimeNamedTypeName(named))
6894
9012
  }
6895
9013
  switch typed := types.Unalias(typ).Underlying().(type) {
6896
9014
  case *types.Basic:
6897
- switch {
6898
- case typed.Info()&types.IsBoolean != 0:
6899
- return "{ kind: " + typeKind + ".Basic, name: \"bool\" }"
6900
- case typed.Info()&types.IsString != 0:
6901
- return "{ kind: " + typeKind + ".Basic, name: \"string\" }"
6902
- case typed.Info()&types.IsNumeric != 0:
6903
- return "{ kind: " + typeKind + ".Basic, name: \"" + basicRuntimeName(typed) + "\" }"
6904
- default:
6905
- return "{ kind: " + typeKind + ".Basic, name: \"unknown\" }"
6906
- }
9015
+ return runtimeBasicTypeInfoExpr(typeKind, typed, "")
6907
9016
  case *types.Pointer:
6908
9017
  return "{ kind: " + typeKind + ".Pointer, elemType: " + o.runtimeTypeInfoExprWithSeen(typed.Elem(), seen) + " }"
6909
9018
  case *types.Struct:
@@ -6926,6 +9035,23 @@ func (o *LoweringOwner) runtimeTypeInfoExprWithSeen(typ types.Type, seen map[typ
6926
9035
  }
6927
9036
  }
6928
9037
 
9038
+ func runtimeBasicTypeInfoExpr(typeKind string, basic *types.Basic, typeName string) string {
9039
+ name := "unknown"
9040
+ switch {
9041
+ case basic.Info()&types.IsBoolean != 0:
9042
+ name = "bool"
9043
+ case basic.Info()&types.IsString != 0:
9044
+ name = "string"
9045
+ case basic.Info()&types.IsNumeric != 0:
9046
+ name = basicRuntimeName(basic)
9047
+ }
9048
+ parts := []string{"kind: " + typeKind + ".Basic", "name: " + strconv.Quote(name)}
9049
+ if typeName != "" {
9050
+ parts = append(parts, "typeName: "+strconv.Quote(typeName))
9051
+ }
9052
+ return "{ " + strings.Join(parts, ", ") + " }"
9053
+ }
9054
+
6929
9055
  func (o *LoweringOwner) shallowRuntimeTypeInfoExpr(typ types.Type) string {
6930
9056
  typeKind := o.runtimeOwner.QualifiedHelper(RuntimeHelperTypeKind)
6931
9057
  switch types.Unalias(typ).Underlying().(type) {
@@ -6998,7 +9124,8 @@ func (o *LoweringOwner) runtimeFunctionTypeInfoWithSeen(signature *types.Signatu
6998
9124
  if signature.Variadic() {
6999
9125
  parts = append(parts, "isVariadic: true")
7000
9126
  }
7001
- return "{ " + strings.Join(parts, ", ") + " }"
9127
+ runtimePackage := strings.TrimSuffix(typeKind, ".TypeKind")
9128
+ return "({ " + strings.Join(parts, ", ") + " } as " + runtimePackage + ".FunctionTypeInfo)"
7002
9129
  }
7003
9130
 
7004
9131
  func (o *LoweringOwner) runtimeSignatureTypes(tuple *types.Tuple, seen map[types.Type]bool) string {
@@ -7012,20 +9139,11 @@ func (o *LoweringOwner) runtimeSignatureTypes(tuple *types.Tuple, seen map[types
7012
9139
  return "[" + strings.Join(types, ", ") + "]"
7013
9140
  }
7014
9141
 
7015
- func fieldByName(structType *types.Struct, name string) *types.Var {
7016
- for field := range structType.Fields() {
7017
- if field.Name() == name {
7018
- return field
7019
- }
7020
- }
7021
- return nil
7022
- }
7023
-
7024
9142
  func tsStructFieldName(name string, idx int) string {
7025
9143
  if name == "_" {
7026
9144
  return "_blank" + strconv.Itoa(idx)
7027
9145
  }
7028
- return name
9146
+ return safeIdentifier(name)
7029
9147
  }
7030
9148
 
7031
9149
  func shouldCloneStructValue(expr ast.Expr) bool {
@@ -7076,6 +9194,11 @@ func (o *LoweringOwner) tsSignatureResultFor(ctx lowerFileContext, signature *ty
7076
9194
  }
7077
9195
 
7078
9196
  func (o *LoweringOwner) tsSignatureResultTypeFor(ctx lowerFileContext, typ types.Type) string {
9197
+ if named, ok := types.Unalias(typ).(*types.Named); ok {
9198
+ if _, ok := types.Unalias(named.Underlying()).(*types.Signature); ok {
9199
+ return o.tsTypeFor(ctx, typ)
9200
+ }
9201
+ }
7079
9202
  if signature := signatureForType(typ); ctx.functionTypeDepth == 0 && signature != nil {
7080
9203
  return o.tsAsyncCompatibleFunctionResultTypeFor(ctx, signature)
7081
9204
  }
@@ -7139,6 +9262,13 @@ func asyncCompatibleResultType(result string) string {
7139
9262
  return result + " | " + tsPromiseType(result)
7140
9263
  }
7141
9264
 
9265
+ func asyncCompatibleMethodResultType(result string, async bool) string {
9266
+ if !async {
9267
+ return result
9268
+ }
9269
+ return asyncCompatibleResultType(result)
9270
+ }
9271
+
7142
9272
  func tsPromiseType(result string) string {
7143
9273
  return "globalThis.Promise<" + result + ">"
7144
9274
  }
@@ -7203,10 +9333,16 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
7203
9333
  if crossPackageUnexportedNamedType(ctx, named) {
7204
9334
  return "any"
7205
9335
  }
9336
+ if !ctx.canReferenceNamedType(named) {
9337
+ return "any"
9338
+ }
7206
9339
  name := o.namedTypeExpr(ctx, named)
7207
9340
  if _, ok := named.Underlying().(*types.Interface); ok {
7208
9341
  return name + " | null"
7209
9342
  }
9343
+ if _, ok := types.Unalias(named.Underlying()).(*types.Signature); ok {
9344
+ return name + " | null"
9345
+ }
7210
9346
  return name
7211
9347
  }
7212
9348
  switch typed := types.Unalias(typ).Underlying().(type) {
@@ -7233,7 +9369,7 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
7233
9369
  }
7234
9370
  return tsArrayType(o.tsTypeFor(ctx, typed.Elem()))
7235
9371
  case *types.Slice:
7236
- return "$.Slice<" + o.tsTypeFor(ctx, typed.Elem()) + ">"
9372
+ return "$.Slice<" + o.tsSliceElemTypeFor(ctx, typed.Elem()) + ">"
7237
9373
  case *types.Map:
7238
9374
  return "Map<" + o.tsTypeFor(ctx, typed.Key()) + ", " + o.tsTypeFor(ctx, typed.Elem()) + "> | null"
7239
9375
  case *types.Chan:
@@ -7251,12 +9387,18 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
7251
9387
  if crossPackageUnexportedNamedType(ctx, named) {
7252
9388
  return "any"
7253
9389
  }
9390
+ if !ctx.canReferenceNamedType(named) {
9391
+ return "any"
9392
+ }
7254
9393
  return "$.VarRef<" + o.namedTypeExpr(ctx, named) + "> | null"
7255
9394
  }
7256
9395
  if named := namedStructType(typed.Elem()); named != nil {
7257
9396
  if crossPackageUnexportedNamedType(ctx, named) {
7258
9397
  return "any"
7259
9398
  }
9399
+ if !ctx.canReferenceNamedType(named) {
9400
+ return "any"
9401
+ }
7260
9402
  name := o.namedTypeExpr(ctx, named)
7261
9403
  return name + " | $.VarRef<" + name + "> | null"
7262
9404
  }
@@ -7272,12 +9414,28 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
7272
9414
  }
7273
9415
  }
7274
9416
 
9417
+ func (o *LoweringOwner) tsSliceElemTypeFor(ctx lowerFileContext, typ types.Type) string {
9418
+ if typeParam, ok := types.Unalias(typ).(*types.TypeParam); ok && staticTypeParamInScope(ctx, typeParam) {
9419
+ return safeIdentifier(typeParam.Obj().Name())
9420
+ }
9421
+ if pointer, ok := types.Unalias(typ).(*types.Pointer); ok {
9422
+ if typeParam, ok := types.Unalias(pointer.Elem()).(*types.TypeParam); ok && staticTypeParamInScope(ctx, typeParam) {
9423
+ name := safeIdentifier(typeParam.Obj().Name())
9424
+ return name + " | $.VarRef<" + name + "> | null"
9425
+ }
9426
+ }
9427
+ return o.tsTypeFor(ctx, typ)
9428
+ }
9429
+
7275
9430
  func (o *LoweringOwner) tsNonNilTypeFor(ctx lowerFileContext, typ types.Type) string {
7276
9431
  if isBuiltinErrorType(typ) {
7277
9432
  return "Exclude<$.GoError, null>"
7278
9433
  }
7279
9434
  if named, ok := types.Unalias(typ).(*types.Named); ok {
7280
9435
  if _, ok := named.Underlying().(*types.Interface); ok {
9436
+ if !ctx.canReferenceNamedType(named) {
9437
+ return "any"
9438
+ }
7281
9439
  return "Exclude<" + o.namedTypeExpr(ctx, named) + ", null>"
7282
9440
  }
7283
9441
  }
@@ -7288,6 +9446,9 @@ func (o *LoweringOwner) aliasTypeExpr(ctx lowerFileContext, alias *types.Alias)
7288
9446
  if alias == nil || alias.Obj() == nil {
7289
9447
  return "unknown"
7290
9448
  }
9449
+ if !ctx.canReferenceObjectPackage(alias.Obj()) {
9450
+ return "any"
9451
+ }
7291
9452
  if alias.Obj().Pkg() == nil {
7292
9453
  return o.tsTypeFor(ctx, alias.Rhs())
7293
9454
  }
@@ -7337,7 +9498,7 @@ func zeroValueExpr(typ types.Type) string {
7337
9498
  return "undefined"
7338
9499
  }
7339
9500
  if named := namedStructType(typ); named != nil && isStructValueType(typ) {
7340
- return "new " + named.Obj().Name() + "()"
9501
+ return "new " + safeIdentifier(named.Obj().Name()) + "()"
7341
9502
  }
7342
9503
  switch typed := types.Unalias(typ).Underlying().(type) {
7343
9504
  case *types.Basic:
@@ -7397,6 +9558,14 @@ func namedStructType(typ types.Type) *types.Named {
7397
9558
  return named
7398
9559
  }
7399
9560
 
9561
+ func pointerToNamedStructType(typ types.Type) *types.Named {
9562
+ pointer, ok := types.Unalias(typ).Underlying().(*types.Pointer)
9563
+ if !ok {
9564
+ return nil
9565
+ }
9566
+ return namedStructType(pointer.Elem())
9567
+ }
9568
+
7400
9569
  func namedNonStructType(typ types.Type) *types.Named {
7401
9570
  named, _ := types.Unalias(typ).(*types.Named)
7402
9571
  if named == nil {
@@ -7458,6 +9627,94 @@ func signatureHasTypeParam(signature *types.Signature, target *types.TypeParam)
7458
9627
  return false
7459
9628
  }
7460
9629
 
9630
+ func typeParamInScope(ctx lowerFileContext, target *types.TypeParam) bool {
9631
+ if target == nil {
9632
+ return false
9633
+ }
9634
+ if signatureHasTypeParam(ctx.signature, target) {
9635
+ return true
9636
+ }
9637
+ return ctx.typeParams[target.Obj().Name()]
9638
+ }
9639
+
9640
+ func staticTypeParamInScope(ctx lowerFileContext, target *types.TypeParam) bool {
9641
+ if target == nil || !typeParamInScope(ctx, target) {
9642
+ return false
9643
+ }
9644
+ return ctx.staticTypeParams[target.Obj().Name()]
9645
+ }
9646
+
9647
+ func typeParamConstraintIsAny(typeParam *types.TypeParam) bool {
9648
+ if typeParam == nil {
9649
+ return false
9650
+ }
9651
+ iface, ok := typeParam.Constraint().Underlying().(*types.Interface)
9652
+ if !ok {
9653
+ return false
9654
+ }
9655
+ return iface.NumMethods() == 0 && iface.NumEmbeddeds() == 0
9656
+ }
9657
+
9658
+ func signatureTypeParamNames(signature *types.Signature) []string {
9659
+ if signature == nil || signature.TypeParams() == nil {
9660
+ return nil
9661
+ }
9662
+ typeParams := signature.TypeParams()
9663
+ names := make([]string, 0, typeParams.Len())
9664
+ for typeParam := range typeParams.TypeParams() {
9665
+ if !signatureUsesTypeParamAsSliceElem(signature, typeParam) {
9666
+ continue
9667
+ }
9668
+ names = append(names, safeIdentifier(typeParam.Obj().Name()))
9669
+ }
9670
+ return names
9671
+ }
9672
+
9673
+ func signatureUsesTypeParamAsSliceElem(signature *types.Signature, target *types.TypeParam) bool {
9674
+ if signature == nil || target == nil {
9675
+ return false
9676
+ }
9677
+ return tupleUsesTypeParamAsSliceElem(signature.Params(), target) ||
9678
+ tupleUsesTypeParamAsSliceElem(signature.Results(), target)
9679
+ }
9680
+
9681
+ func tupleUsesTypeParamAsSliceElem(tuple *types.Tuple, target *types.TypeParam) bool {
9682
+ if tuple == nil {
9683
+ return false
9684
+ }
9685
+ for variable := range tuple.Variables() {
9686
+ if typeUsesTypeParamAsSliceElem(variable.Type(), target) {
9687
+ return true
9688
+ }
9689
+ }
9690
+ return false
9691
+ }
9692
+
9693
+ func typeUsesTypeParamAsSliceElem(typ types.Type, target *types.TypeParam) bool {
9694
+ switch typed := types.Unalias(typ).Underlying().(type) {
9695
+ case *types.Slice:
9696
+ if typeParam, ok := types.Unalias(typed.Elem()).(*types.TypeParam); ok &&
9697
+ (typeParam == target || typeParam.Obj() == target.Obj()) {
9698
+ return true
9699
+ }
9700
+ return typeUsesTypeParamAsSliceElem(typed.Elem(), target)
9701
+ case *types.Array:
9702
+ return typeUsesTypeParamAsSliceElem(typed.Elem(), target)
9703
+ case *types.Pointer:
9704
+ return typeUsesTypeParamAsSliceElem(typed.Elem(), target)
9705
+ case *types.Map:
9706
+ return typeUsesTypeParamAsSliceElem(typed.Key(), target) ||
9707
+ typeUsesTypeParamAsSliceElem(typed.Elem(), target)
9708
+ case *types.Chan:
9709
+ return typeUsesTypeParamAsSliceElem(typed.Elem(), target)
9710
+ case *types.Signature:
9711
+ return tupleUsesTypeParamAsSliceElem(typed.Params(), target) ||
9712
+ tupleUsesTypeParamAsSliceElem(typed.Results(), target)
9713
+ default:
9714
+ return false
9715
+ }
9716
+ }
9717
+
7461
9718
  func sameNamedTypeOrigin(a *types.Named, b *types.Named) bool {
7462
9719
  if a == nil || b == nil {
7463
9720
  return false
@@ -7585,6 +9842,11 @@ func isIntegerType(typ types.Type) bool {
7585
9842
  return ok && basic.Info()&types.IsInteger != 0
7586
9843
  }
7587
9844
 
9845
+ func isFloatType(typ types.Type) bool {
9846
+ basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
9847
+ return ok && basic.Info()&types.IsFloat != 0
9848
+ }
9849
+
7588
9850
  func unsignedIntegerBits(typ types.Type) (int, bool) {
7589
9851
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
7590
9852
  if !ok || basic.Info()&types.IsUnsigned == 0 {
@@ -7632,6 +9894,9 @@ func isWideIntegerType(typ types.Type) bool {
7632
9894
  }
7633
9895
 
7634
9896
  func isFixedWideIntegerType(typ types.Type) bool {
9897
+ if typ == nil {
9898
+ return false
9899
+ }
7635
9900
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
7636
9901
  if !ok {
7637
9902
  return false
@@ -7644,6 +9909,14 @@ func isFixedWideIntegerType(typ types.Type) bool {
7644
9909
  }
7645
9910
  }
7646
9911
 
9912
+ func isFixedSignedWideIntegerType(typ types.Type) bool {
9913
+ if typ == nil {
9914
+ return false
9915
+ }
9916
+ basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
9917
+ return ok && basic.Kind() == types.Int64
9918
+ }
9919
+
7647
9920
  func isRuneSliceType(typ types.Type) bool {
7648
9921
  slice, ok := types.Unalias(typ).Underlying().(*types.Slice)
7649
9922
  return ok && isRuneType(slice.Elem())
@@ -7672,6 +9945,8 @@ func sliceTypeHint(typ types.Type) string {
7672
9945
  return "string"
7673
9946
  case isNumericType(typ):
7674
9947
  return "number"
9948
+ case isBoolType(typ):
9949
+ return "boolean"
7675
9950
  default:
7676
9951
  return ""
7677
9952
  }
@@ -7800,6 +10075,13 @@ func (o *LoweringOwner) awaitCallIfNeeded(ctx lowerFileContext, fun ast.Expr, ca
7800
10075
  return call
7801
10076
  }
7802
10077
 
10078
+ func parenthesizeAwaitedExpr(expr string) string {
10079
+ if strings.HasPrefix(expr, "await ") {
10080
+ return "(" + expr + ")"
10081
+ }
10082
+ return expr
10083
+ }
10084
+
7803
10085
  func (o *LoweringOwner) genericTypeArgsExpr(ctx lowerFileContext, callee ast.Expr, typeArgExprs []ast.Expr) string {
7804
10086
  signature := genericFunctionSignature(ctx, callee)
7805
10087
  if signature == nil {
@@ -7883,7 +10165,7 @@ func (o *LoweringOwner) inferGenericTypeArg(
7883
10165
  }
7884
10166
 
7885
10167
  func (o *LoweringOwner) genericTypeDescriptorExpr(ctx lowerFileContext, typ types.Type) string {
7886
- if typeParam, ok := types.Unalias(typ).(*types.TypeParam); ok && signatureHasTypeParam(ctx.signature, typeParam) {
10168
+ if typeParam, ok := types.Unalias(typ).(*types.TypeParam); ok && typeParamInScope(ctx, typeParam) {
7887
10169
  return "__typeArgs?.[" + strconv.Quote(typeParam.Obj().Name()) + "] ?? { type: " +
7888
10170
  o.runtimeTypeInfoExpr(typ) + ", zero: () => " + o.lowerZeroValueExprFor(ctx, typ) + " }"
7889
10171
  }
@@ -7921,7 +10203,21 @@ func (o *LoweringOwner) genericMethodDescriptorsForType(
7921
10203
  methods = append(methods, method.Name()+": (receiver: any, ...args: any[]) => receiver."+method.Name()+"(...args)")
7922
10204
  continue
7923
10205
  }
7924
- methods = append(methods, method.Name()+": "+o.methodFunctionExpr(ctx, named.Origin(), method, method.Name()))
10206
+ receiver := "receiver"
10207
+ if sig, _ := method.Type().(*types.Signature); sig != nil {
10208
+ if recv := sig.Recv(); recv != nil {
10209
+ if _, ok := types.Unalias(recv.Type()).Underlying().(*types.Pointer); !ok {
10210
+ if _, ok := types.Unalias(methodSetType).Underlying().(*types.Pointer); ok {
10211
+ receiver = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + "(receiver)"
10212
+ } else {
10213
+ receiver = "(" + o.runtimeOwner.QualifiedHelper(RuntimeHelperIsVarRef) +
10214
+ "(receiver) ? receiver.value : receiver)"
10215
+ }
10216
+ }
10217
+ }
10218
+ }
10219
+ methods = append(methods, method.Name()+": (receiver: any, ...args: any[]) => "+
10220
+ "("+o.methodFunctionExpr(ctx, named.Origin(), method, method.Name())+" as any)("+receiver+", ...args)")
7925
10221
  }
7926
10222
  if len(methods) == 0 {
7927
10223
  return ""
@@ -7946,9 +10242,21 @@ func namedNonStructMethodSetType(typ types.Type) (*types.Named, types.Type) {
7946
10242
 
7947
10243
  func methodFunctionName(receiver *types.Named, method string) string {
7948
10244
  if receiver == nil || receiver.Obj() == nil {
7949
- return method
10245
+ return safeIdentifier(method)
10246
+ }
10247
+ return safeIdentifier(receiver.Obj().Name()) + "_" + safeIdentifier(method)
10248
+ }
10249
+
10250
+ func methodReceiverNamedType(obj types.Object) *types.Named {
10251
+ fn, _ := obj.(*types.Func)
10252
+ if fn == nil {
10253
+ return nil
10254
+ }
10255
+ signature, _ := fn.Type().(*types.Signature)
10256
+ if signature == nil || signature.Recv() == nil {
10257
+ return nil
7950
10258
  }
7951
- return receiver.Obj().Name() + "_" + method
10259
+ return receiverNamedType(signature.Recv().Type())
7952
10260
  }
7953
10261
 
7954
10262
  func (o *LoweringOwner) methodFunctionExpr(
@@ -7973,7 +10281,7 @@ func (o *LoweringOwner) namedTypeExpr(ctx lowerFileContext, named *types.Named)
7973
10281
  if named == nil || named.Obj() == nil {
7974
10282
  return "unknown"
7975
10283
  }
7976
- baseName := named.Obj().Name()
10284
+ baseName := safeIdentifier(named.Obj().Name())
7977
10285
  if alias := ctx.localAliases[named.Obj()]; alias != "" {
7978
10286
  baseName = alias + "." + baseName
7979
10287
  } else if named.Obj().Pkg() != nil {
@@ -8036,11 +10344,30 @@ func runtimeNamedTypeName(named *types.Named) string {
8036
10344
  }
8037
10345
 
8038
10346
  func goRuntimeTypeString(typ types.Type) string {
8039
- return types.TypeString(typ, func(pkg *types.Package) string {
10347
+ return types.TypeString(runtimeIdentityType(typ), func(pkg *types.Package) string {
8040
10348
  return pkg.Name()
8041
10349
  })
8042
10350
  }
8043
10351
 
10352
+ func runtimeIdentityType(typ types.Type) types.Type {
10353
+ switch typed := typ.(type) {
10354
+ case *types.Alias:
10355
+ return runtimeIdentityType(types.Unalias(typed))
10356
+ case *types.Pointer:
10357
+ return types.NewPointer(runtimeIdentityType(typed.Elem()))
10358
+ case *types.Slice:
10359
+ return types.NewSlice(runtimeIdentityType(typed.Elem()))
10360
+ case *types.Array:
10361
+ return types.NewArray(runtimeIdentityType(typed.Elem()), typed.Len())
10362
+ case *types.Map:
10363
+ return types.NewMap(runtimeIdentityType(typed.Key()), runtimeIdentityType(typed.Elem()))
10364
+ case *types.Chan:
10365
+ return types.NewChan(typed.Dir(), runtimeIdentityType(typed.Elem()))
10366
+ default:
10367
+ return typ
10368
+ }
10369
+ }
10370
+
8044
10371
  func basicRuntimeName(basic *types.Basic) string {
8045
10372
  if basic == nil {
8046
10373
  return "unknown"