goscript 0.1.1 → 0.1.2

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 (356) 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 +9 -2
  13. package/compiler/lowering.go +2001 -345
  14. package/compiler/override-facts.go +77 -27
  15. package/compiler/override-registry.go +5 -4
  16. package/compiler/override-registry_test.go +135 -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 +1921 -298
  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 +122 -9
  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 +107 -25
  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 +47 -7
  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/iter.gs.js +13 -13
  58. package/dist/gs/bytes/iter.gs.js.map +1 -1
  59. package/dist/gs/compress/zlib/index.d.ts +26 -0
  60. package/dist/gs/compress/zlib/index.js +168 -0
  61. package/dist/gs/compress/zlib/index.js.map +1 -0
  62. package/dist/gs/context/context.d.ts +1 -1
  63. package/dist/gs/context/context.js +8 -3
  64. package/dist/gs/context/context.js.map +1 -1
  65. package/dist/gs/crypto/ecdh/index.d.ts +52 -0
  66. package/dist/gs/crypto/ecdh/index.js +226 -0
  67. package/dist/gs/crypto/ecdh/index.js.map +1 -0
  68. package/dist/gs/crypto/ed25519/index.d.ts +34 -0
  69. package/dist/gs/crypto/ed25519/index.js +160 -0
  70. package/dist/gs/crypto/ed25519/index.js.map +1 -0
  71. package/dist/gs/crypto/internal/constanttime/index.d.ts +4 -0
  72. package/dist/gs/crypto/internal/constanttime/index.js +18 -0
  73. package/dist/gs/crypto/internal/constanttime/index.js.map +1 -0
  74. package/dist/gs/crypto/rand/index.d.ts +2 -0
  75. package/dist/gs/crypto/rand/index.js +85 -0
  76. package/dist/gs/crypto/rand/index.js.map +1 -1
  77. package/dist/gs/crypto/sha256/index.d.ts +8 -0
  78. package/dist/gs/crypto/sha256/index.js +118 -0
  79. package/dist/gs/crypto/sha256/index.js.map +1 -0
  80. package/dist/gs/crypto/sha512/index.d.ts +14 -0
  81. package/dist/gs/crypto/sha512/index.js +129 -0
  82. package/dist/gs/crypto/sha512/index.js.map +1 -0
  83. package/dist/gs/encoding/json/index.d.ts +3 -0
  84. package/dist/gs/encoding/json/index.js +15 -0
  85. package/dist/gs/encoding/json/index.js.map +1 -1
  86. package/dist/gs/errors/errors.js +29 -6
  87. package/dist/gs/errors/errors.js.map +1 -1
  88. package/dist/gs/fmt/fmt.js.map +1 -1
  89. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +7 -7
  90. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +52 -18
  91. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  92. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +56 -20
  93. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -1
  94. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +57 -3
  95. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +366 -1
  96. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
  97. package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +20 -0
  98. package/dist/gs/github.com/aperturerobotics/util/conc/index.js +134 -0
  99. package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +1 -0
  100. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
  101. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.d.ts +3 -0
  102. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js +50 -0
  103. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js.map +1 -0
  104. package/dist/gs/github.com/klauspost/compress/internal/le/index.js +3 -2
  105. package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -1
  106. package/dist/gs/github.com/mr-tron/base58/base58/index.d.ts +27 -0
  107. package/dist/gs/github.com/mr-tron/base58/base58/index.js +172 -0
  108. package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -0
  109. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.d.ts +21 -0
  110. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js +22 -0
  111. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js.map +1 -0
  112. package/dist/gs/go/token/index.js +11 -4
  113. package/dist/gs/go/token/index.js.map +1 -1
  114. package/dist/gs/hash/fnv/index.d.ts +57 -0
  115. package/dist/gs/hash/fnv/index.js +299 -0
  116. package/dist/gs/hash/fnv/index.js.map +1 -0
  117. package/dist/gs/hash/index.d.ts +17 -0
  118. package/dist/gs/hash/index.js +94 -0
  119. package/dist/gs/hash/index.js.map +1 -0
  120. package/dist/gs/io/fs/readlink.js +2 -6
  121. package/dist/gs/io/fs/readlink.js.map +1 -1
  122. package/dist/gs/io/fs/walk.js.map +1 -1
  123. package/dist/gs/io/io.js.map +1 -1
  124. package/dist/gs/iter/iter.d.ts +3 -2
  125. package/dist/gs/iter/iter.js.map +1 -1
  126. package/dist/gs/maps/iter.d.ts +5 -5
  127. package/dist/gs/maps/iter.js +48 -21
  128. package/dist/gs/maps/iter.js.map +1 -1
  129. package/dist/gs/maps/maps.d.ts +6 -6
  130. package/dist/gs/math/bits/index.js +14 -24
  131. package/dist/gs/math/bits/index.js.map +1 -1
  132. package/dist/gs/mime/index.js +3 -1
  133. package/dist/gs/mime/index.js.map +1 -1
  134. package/dist/gs/net/http/httptest/index.d.ts +20 -1
  135. package/dist/gs/net/http/httptest/index.js +83 -3
  136. package/dist/gs/net/http/httptest/index.js.map +1 -1
  137. package/dist/gs/net/http/index.d.ts +110 -6
  138. package/dist/gs/net/http/index.js +262 -16
  139. package/dist/gs/net/http/index.js.map +1 -1
  140. package/dist/gs/net/http/pprof/index.d.ts +8 -0
  141. package/dist/gs/net/http/pprof/index.js +59 -0
  142. package/dist/gs/net/http/pprof/index.js.map +1 -0
  143. package/dist/gs/os/error.gs.js +9 -7
  144. package/dist/gs/os/error.gs.js.map +1 -1
  145. package/dist/gs/os/types_js.gs.js +95 -15
  146. package/dist/gs/os/types_js.gs.js.map +1 -1
  147. package/dist/gs/path/filepath/match.js.map +1 -1
  148. package/dist/gs/path/filepath/path.d.ts +5 -3
  149. package/dist/gs/path/filepath/path.js +65 -10
  150. package/dist/gs/path/filepath/path.js.map +1 -1
  151. package/dist/gs/reflect/index.d.ts +3 -2
  152. package/dist/gs/reflect/index.js +2 -1
  153. package/dist/gs/reflect/index.js.map +1 -1
  154. package/dist/gs/reflect/iter.js +2 -2
  155. package/dist/gs/reflect/iter.js.map +1 -1
  156. package/dist/gs/reflect/map.js +26 -0
  157. package/dist/gs/reflect/map.js.map +1 -1
  158. package/dist/gs/reflect/type.d.ts +24 -5
  159. package/dist/gs/reflect/type.js +390 -38
  160. package/dist/gs/reflect/type.js.map +1 -1
  161. package/dist/gs/reflect/types.d.ts +1 -0
  162. package/dist/gs/reflect/types.js +3 -1
  163. package/dist/gs/reflect/types.js.map +1 -1
  164. package/dist/gs/reflect/value.d.ts +4 -1
  165. package/dist/gs/reflect/value.js +39 -1
  166. package/dist/gs/reflect/value.js.map +1 -1
  167. package/dist/gs/reflect/visiblefields.js +1 -1
  168. package/dist/gs/reflect/visiblefields.js.map +1 -1
  169. package/dist/gs/runtime/debug/index.d.ts +39 -0
  170. package/dist/gs/runtime/debug/index.js +58 -0
  171. package/dist/gs/runtime/debug/index.js.map +1 -1
  172. package/dist/gs/runtime/pprof/index.d.ts +20 -0
  173. package/dist/gs/runtime/pprof/index.js +85 -0
  174. package/dist/gs/runtime/pprof/index.js.map +1 -0
  175. package/dist/gs/runtime/trace/index.d.ts +19 -0
  176. package/dist/gs/runtime/trace/index.js +64 -0
  177. package/dist/gs/runtime/trace/index.js.map +1 -0
  178. package/dist/gs/slices/slices.d.ts +24 -9
  179. package/dist/gs/slices/slices.js +229 -24
  180. package/dist/gs/slices/slices.js.map +1 -1
  181. package/dist/gs/sort/slice.gs.d.ts +5 -3
  182. package/dist/gs/sort/slice.gs.js +55 -17
  183. package/dist/gs/sort/slice.gs.js.map +1 -1
  184. package/dist/gs/strings/builder.js +26 -17
  185. package/dist/gs/strings/builder.js.map +1 -1
  186. package/dist/gs/strings/iter.js +140 -75
  187. package/dist/gs/strings/iter.js.map +1 -1
  188. package/dist/gs/strings/replace.js +2 -2
  189. package/dist/gs/strings/replace.js.map +1 -1
  190. package/dist/gs/strings/strings.js +52 -6
  191. package/dist/gs/strings/strings.js.map +1 -1
  192. package/dist/gs/sync/sync.d.ts +6 -3
  193. package/dist/gs/sync/sync.js +39 -11
  194. package/dist/gs/sync/sync.js.map +1 -1
  195. package/dist/gs/syscall/errors.d.ts +116 -112
  196. package/dist/gs/syscall/errors.js +38 -1
  197. package/dist/gs/syscall/errors.js.map +1 -1
  198. package/dist/gs/syscall/fs.d.ts +2 -8
  199. package/dist/gs/syscall/fs.js.map +1 -1
  200. package/dist/gs/syscall/js/index.js +20 -12
  201. package/dist/gs/syscall/js/index.js.map +1 -1
  202. package/dist/gs/syscall/types.d.ts +4 -1
  203. package/dist/gs/syscall/types.js.map +1 -1
  204. package/dist/gs/testing/testing.d.ts +4 -3
  205. package/dist/gs/testing/testing.js +21 -4
  206. package/dist/gs/testing/testing.js.map +1 -1
  207. package/dist/gs/time/time.js +22 -0
  208. package/dist/gs/time/time.js.map +1 -1
  209. package/dist/gs/unicode/unicode.js.map +1 -1
  210. package/dist/gs/unique/index.js +7 -2
  211. package/dist/gs/unique/index.js.map +1 -1
  212. package/go.mod +8 -8
  213. package/go.sum +14 -23
  214. package/gs/builtin/builtin.ts +364 -37
  215. package/gs/builtin/channel.ts +161 -29
  216. package/gs/builtin/defer.ts +13 -2
  217. package/gs/builtin/hostio.test.ts +1 -0
  218. package/gs/builtin/hostio.ts +38 -0
  219. package/gs/builtin/map.ts +46 -6
  220. package/gs/builtin/print.ts +12 -3
  221. package/gs/builtin/runtime-contract.test.ts +257 -10
  222. package/gs/builtin/slice.test.ts +70 -0
  223. package/gs/builtin/slice.ts +566 -255
  224. package/gs/builtin/type.ts +53 -9
  225. package/gs/builtin/varRef.ts +2 -0
  226. package/gs/bytes/buffer.gs.ts +28 -28
  227. package/gs/bytes/iter.gs.ts +13 -14
  228. package/gs/compress/zlib/index.test.ts +28 -0
  229. package/gs/compress/zlib/index.ts +200 -0
  230. package/gs/compress/zlib/meta.json +3 -0
  231. package/gs/context/context.test.ts +31 -1
  232. package/gs/context/context.ts +9 -4
  233. package/gs/crypto/ecdh/index.test.ts +43 -0
  234. package/gs/crypto/ecdh/index.ts +274 -0
  235. package/gs/crypto/ed25519/index.test.ts +41 -0
  236. package/gs/crypto/ed25519/index.ts +238 -0
  237. package/gs/crypto/ed25519/meta.json +13 -0
  238. package/gs/crypto/internal/constanttime/index.test.ts +25 -0
  239. package/gs/crypto/internal/constanttime/index.ts +22 -0
  240. package/gs/crypto/rand/index.test.ts +89 -1
  241. package/gs/crypto/rand/index.ts +103 -1
  242. package/gs/crypto/rand/meta.json +4 -1
  243. package/gs/crypto/sha256/index.test.ts +78 -0
  244. package/gs/crypto/sha256/index.ts +150 -0
  245. package/gs/crypto/sha256/meta.json +9 -0
  246. package/gs/crypto/sha512/index.test.ts +31 -0
  247. package/gs/crypto/sha512/index.ts +161 -0
  248. package/gs/crypto/sha512/meta.json +11 -0
  249. package/gs/encoding/json/index.test.ts +25 -3
  250. package/gs/encoding/json/index.ts +21 -3
  251. package/gs/errors/errors.test.ts +4 -1
  252. package/gs/errors/errors.ts +32 -8
  253. package/gs/fmt/fmt.test.ts +3 -1
  254. package/gs/fmt/fmt.ts +1 -5
  255. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +62 -7
  256. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +78 -36
  257. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +32 -11
  258. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +122 -43
  259. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +31 -0
  260. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +518 -4
  261. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +6 -0
  262. package/gs/github.com/aperturerobotics/util/conc/index.test.ts +30 -0
  263. package/gs/github.com/aperturerobotics/util/conc/index.ts +172 -0
  264. package/gs/github.com/aperturerobotics/util/conc/meta.json +9 -0
  265. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.ts +1 -4
  266. package/gs/github.com/hack-pad/safejs/internal/catch/index.test.ts +35 -0
  267. package/gs/github.com/hack-pad/safejs/internal/catch/index.ts +65 -0
  268. package/gs/github.com/hack-pad/safejs/internal/catch/meta.json +9 -0
  269. package/gs/github.com/klauspost/compress/internal/le/index.test.ts +2 -1
  270. package/gs/github.com/klauspost/compress/internal/le/index.ts +6 -5
  271. package/gs/github.com/mr-tron/base58/base58/index.test.ts +70 -0
  272. package/gs/github.com/mr-tron/base58/base58/index.ts +231 -0
  273. package/gs/github.com/mr-tron/base58/base58/meta.json +3 -0
  274. package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +46 -0
  275. package/gs/github.com/zeebo/blake3/internal/consts/index.ts +26 -0
  276. package/gs/go/token/index.ts +17 -4
  277. package/gs/hash/fnv/index.test.ts +67 -0
  278. package/gs/hash/fnv/index.ts +351 -0
  279. package/gs/hash/fnv/meta.json +3 -0
  280. package/gs/hash/index.test.ts +37 -0
  281. package/gs/hash/index.ts +118 -0
  282. package/gs/hash/meta.json +5 -0
  283. package/gs/internal/byteorder/index.test.ts +6 -6
  284. package/gs/io/fs/readlink.ts +40 -48
  285. package/gs/io/fs/walk.ts +10 -2
  286. package/gs/io/io.ts +4 -1
  287. package/gs/iter/iter.ts +8 -2
  288. package/gs/maps/iter.ts +69 -26
  289. package/gs/maps/maps.test.ts +23 -0
  290. package/gs/maps/maps.ts +6 -6
  291. package/gs/math/bits/index.test.ts +20 -0
  292. package/gs/math/bits/index.ts +15 -28
  293. package/gs/mime/index.ts +8 -2
  294. package/gs/net/http/httptest/index.test.ts +53 -0
  295. package/gs/net/http/httptest/index.ts +98 -3
  296. package/gs/net/http/index.test.ts +129 -1
  297. package/gs/net/http/index.ts +370 -19
  298. package/gs/net/http/meta.json +6 -0
  299. package/gs/net/http/pprof/index.test.ts +47 -0
  300. package/gs/net/http/pprof/index.ts +65 -0
  301. package/gs/os/error.gs.ts +9 -10
  302. package/gs/os/error.test.ts +41 -0
  303. package/gs/os/file_unix_js.test.ts +55 -0
  304. package/gs/os/tempfile.gs.test.ts +37 -10
  305. package/gs/os/types_js.gs.ts +94 -15
  306. package/gs/path/filepath/match.ts +4 -1
  307. package/gs/path/filepath/meta.json +6 -0
  308. package/gs/path/filepath/path.test.ts +57 -2
  309. package/gs/path/filepath/path.ts +91 -12
  310. package/gs/reflect/field.test.ts +63 -0
  311. package/gs/reflect/index.ts +4 -1
  312. package/gs/reflect/iter.ts +2 -2
  313. package/gs/reflect/map.test.ts +24 -2
  314. package/gs/reflect/map.ts +35 -0
  315. package/gs/reflect/type.ts +543 -60
  316. package/gs/reflect/typefor.test.ts +100 -0
  317. package/gs/reflect/types.ts +3 -1
  318. package/gs/reflect/value.ts +50 -1
  319. package/gs/reflect/visiblefields.ts +1 -1
  320. package/gs/runtime/debug/index.test.ts +22 -1
  321. package/gs/runtime/debug/index.ts +88 -0
  322. package/gs/runtime/pprof/index.test.ts +36 -0
  323. package/gs/runtime/pprof/index.ts +104 -0
  324. package/gs/runtime/pprof/meta.json +6 -0
  325. package/gs/runtime/trace/index.test.ts +45 -0
  326. package/gs/runtime/trace/index.ts +97 -0
  327. package/gs/runtime/trace/meta.json +7 -0
  328. package/gs/slices/meta.json +2 -1
  329. package/gs/slices/slices.test.ts +86 -0
  330. package/gs/slices/slices.ts +284 -37
  331. package/gs/sort/slice.gs.ts +73 -23
  332. package/gs/sort/slice.test.ts +40 -0
  333. package/gs/strings/builder.test.ts +8 -0
  334. package/gs/strings/builder.ts +29 -17
  335. package/gs/strings/iter.test.ts +5 -7
  336. package/gs/strings/iter.ts +146 -71
  337. package/gs/strings/replace.test.ts +1 -4
  338. package/gs/strings/replace.ts +6 -6
  339. package/gs/strings/strings.test.ts +4 -0
  340. package/gs/strings/strings.ts +54 -6
  341. package/gs/sync/sync.test.ts +57 -1
  342. package/gs/sync/sync.ts +45 -13
  343. package/gs/syscall/errors.ts +158 -115
  344. package/gs/syscall/fs.ts +8 -8
  345. package/gs/syscall/js/index.ts +49 -22
  346. package/gs/syscall/net.test.ts +26 -0
  347. package/gs/syscall/types.ts +7 -2
  348. package/gs/testing/testing.test.ts +56 -0
  349. package/gs/testing/testing.ts +27 -10
  350. package/gs/time/meta.json +2 -2
  351. package/gs/time/time.test.ts +4 -0
  352. package/gs/time/time.ts +33 -2
  353. package/gs/unicode/unicode.test.ts +14 -3
  354. package/gs/unicode/unicode.ts +1 -5
  355. package/gs/unique/index.ts +9 -2
  356. 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,19 +179,19 @@ 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
190
  for importSourcePath := range relevantImportFiles {
180
191
  o.addGeneratedTypeImports(model, semPkg, importSourcePath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport)
181
192
  }
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 {
193
+ implicitImportPaths := make([]string, 0, len(localRefs.implicitImports))
194
+ for pkgPath := range localRefs.implicitImports {
186
195
  if pkgPath != "" && pkgPath != semPkg.pkgPath {
187
196
  implicitImportPaths = append(implicitImportPaths, pkgPath)
188
197
  }
@@ -191,15 +200,15 @@ func (o *LoweringOwner) lowerFile(
191
200
  for _, pkgPath := range implicitImportPaths {
192
201
  o.addGeneratedImportPath(model, pkgPath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport)
193
202
  }
194
- localImports := make([]loweredImport, 0, len(localAliases))
203
+ localImports := make([]loweredImport, 0, len(localRefs.aliases))
195
204
  seenLocalImport := make(map[string]bool)
196
- for _, alias := range localAliases {
205
+ for _, alias := range localRefs.aliases {
197
206
  if seenLocalImport[alias] {
198
207
  continue
199
208
  }
200
209
  seenLocalImport[alias] = true
201
- source := localAliasSources[alias]
202
- localImports = append(localImports, loweredImport{alias: alias, source: source})
210
+ source := localRefs.aliasSources[alias]
211
+ localImports = append(localImports, loweredImport{alias: alias, source: source, sideEffect: true})
203
212
  }
204
213
  slices.SortFunc(localImports, func(a, b loweredImport) int {
205
214
  return cmp.Compare(a.alias, b.alias)
@@ -213,15 +222,21 @@ func (o *LoweringOwner) lowerFile(
213
222
  importAliases: importAliases,
214
223
  importPaths: importPaths,
215
224
  importNames: importNames,
225
+ importObjects: importObjects,
216
226
  sourcePath: sourcePath,
217
- localAliases: localAliases,
227
+ localAliases: localRefs.aliases,
218
228
  lazyPackageVars: lazyPackageVars,
219
229
  tempNames: newTempNameOwner(),
220
230
  topLevel: true,
221
231
  }
222
232
  var diagnostics []Diagnostic
233
+ var packageInitCalls []string
223
234
  appendDecls := func(decls []loweredDecl) {
224
235
  for _, decl := range decls {
236
+ if decl.packageInitCall != "" {
237
+ packageInitCalls = append(packageInitCalls, decl.packageInitCall)
238
+ continue
239
+ }
225
240
  loweredFile.decls = append(loweredFile.decls, decl)
226
241
  if decl.indexExport != "" {
227
242
  loweredFile.exports = append(loweredFile.exports, decl.indexExport)
@@ -229,6 +244,9 @@ func (o *LoweringOwner) lowerFile(
229
244
  if decl.typeIndexExport != "" {
230
245
  loweredFile.typeExports = append(loweredFile.typeExports, decl.typeIndexExport)
231
246
  }
247
+ if decl.sideEffect {
248
+ loweredFile.sideEffect = true
249
+ }
232
250
  if decl.function != nil && decl.function.indexExported && decl.function.name != "main" {
233
251
  loweredFile.exports = append(loweredFile.exports, decl.function.name)
234
252
  }
@@ -252,6 +270,9 @@ func (o *LoweringOwner) lowerFile(
252
270
  lowerDecl(decl)
253
271
  }
254
272
  }
273
+ for _, call := range packageInitCalls {
274
+ loweredFile.decls = append(loweredFile.decls, loweredDecl{code: "await " + call})
275
+ }
255
276
  for _, decl := range loweredFile.decls {
256
277
  if decl.function == nil || !decl.function.init {
257
278
  continue
@@ -317,8 +338,9 @@ func (o *LoweringOwner) addGeneratedImportPath(
317
338
  importAliases[alias] = pkgPath
318
339
  importPaths[pkgPath] = alias
319
340
  loweredFile.imports = append(loweredFile.imports, loweredImport{
320
- alias: alias,
321
- source: source,
341
+ alias: alias,
342
+ source: source,
343
+ sideEffect: true,
322
344
  })
323
345
  }
324
346
 
@@ -351,36 +373,6 @@ func uniqueImportAlias(alias string, pkgPath string, importAliases map[string]st
351
373
  }
352
374
  }
353
375
 
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
376
  func (o *LoweringOwner) methodDeclsForFileTypes(semPkg *semanticPackage, file *ast.File) []*ast.FuncDecl {
385
377
  if semPkg == nil || semPkg.source == nil || file == nil {
386
378
  return nil
@@ -433,27 +425,27 @@ func (o *LoweringOwner) methodDeclsForFileTypes(semPkg *semanticPackage, file *a
433
425
  return methods
434
426
  }
435
427
 
436
- func (o *LoweringOwner) localFileAliases(
428
+ type localFileReferenceAnalysis struct {
429
+ reservedNames map[string]bool
430
+ aliases map[types.Object]string
431
+ aliasSources map[string]string
432
+ implicitImports map[string]bool
433
+ }
434
+
435
+ func (o *LoweringOwner) analyzeLocalFileReferences(
437
436
  semPkg *semanticPackage,
438
437
  file *ast.File,
439
438
  sourcePath string,
440
439
  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)
440
+ declFiles map[types.Object]string,
441
+ outputNames map[string]string,
442
+ ) localFileReferenceAnalysis {
443
+ analysis := localFileReferenceAnalysis{
444
+ reservedNames: make(map[string]bool),
445
+ aliases: make(map[types.Object]string),
446
+ aliasSources: make(map[string]string),
447
+ implicitImports: make(map[string]bool),
453
448
  }
454
- aliases := make(map[types.Object]string)
455
- aliasSources := make(map[string]string)
456
- implicitImports := make(map[string]bool)
457
449
  seenObjects := make(map[types.Object]bool)
458
450
  seenTypes := make(map[types.Type]bool)
459
451
  var addTypeDeps func(typ types.Type)
@@ -471,8 +463,8 @@ func (o *LoweringOwner) localFileAliases(
471
463
  outputName := outputNames[declFile]
472
464
  if outputName != "" {
473
465
  alias := "__goscript_" + safeIdentifier(strings.TrimSuffix(outputName, ".gs.ts"))
474
- aliases[obj] = alias
475
- aliasSources[alias] = "./" + outputName
466
+ analysis.aliases[obj] = alias
467
+ analysis.aliasSources[alias] = "./" + outputName
476
468
  }
477
469
  }
478
470
  switch typed := obj.(type) {
@@ -514,7 +506,7 @@ func (o *LoweringOwner) localFileAliases(
514
506
  seenTypes[typ] = true
515
507
  if alias, ok := typ.(*types.Alias); ok {
516
508
  if obj := alias.Obj(); obj != nil && obj.Pkg() != nil && obj.Pkg().Path() != semPkg.pkgPath {
517
- implicitImports[obj.Pkg().Path()] = true
509
+ analysis.implicitImports[obj.Pkg().Path()] = true
518
510
  if args := alias.TypeArgs(); args != nil {
519
511
  for t := range args.Types() {
520
512
  addTypeDeps(t)
@@ -534,7 +526,7 @@ func (o *LoweringOwner) localFileAliases(
534
526
  }
535
527
  if named, ok := types.Unalias(typ).(*types.Named); ok {
536
528
  if obj := named.Obj(); obj != nil && obj.Pkg() != nil && obj.Pkg().Path() != semPkg.pkgPath {
537
- implicitImports[obj.Pkg().Path()] = true
529
+ analysis.implicitImports[obj.Pkg().Path()] = true
538
530
  if args := named.TypeArgs(); args != nil {
539
531
  for t := range args.Types() {
540
532
  addTypeDeps(t)
@@ -591,11 +583,20 @@ func (o *LoweringOwner) localFileAliases(
591
583
  inspect := func(node ast.Node) bool {
592
584
  switch typed := node.(type) {
593
585
  case *ast.Ident:
586
+ if obj := semPkg.source.TypesInfo.Defs[typed]; obj != nil {
587
+ if _, ok := obj.(*types.PkgName); !ok {
588
+ name := safeIdentifier(obj.Name())
589
+ if name != "_" {
590
+ analysis.reservedNames[name] = true
591
+ }
592
+ }
593
+ }
594
594
  addObject(semPkg.source.TypesInfo.Uses[typed])
595
595
  addTypeDeps(semPkg.source.TypesInfo.TypeOf(typed))
596
596
  case *ast.SelectorExpr:
597
597
  if selection := semPkg.source.TypesInfo.Selections[typed]; selection != nil {
598
598
  addObject(selection.Obj())
599
+ addTypeDeps(selection.Obj().Type())
599
600
  } else if obj := semPkg.source.TypesInfo.Uses[typed.Sel]; obj != nil {
600
601
  addTypeDeps(obj.Type())
601
602
  }
@@ -609,7 +610,7 @@ func (o *LoweringOwner) localFileAliases(
609
610
  for _, methodDecl := range associatedMethods {
610
611
  ast.Inspect(methodDecl, inspect)
611
612
  }
612
- return aliases, aliasSources, implicitImports
613
+ return analysis
613
614
  }
614
615
 
615
616
  func safeIdentifier(value string) string {
@@ -668,12 +669,16 @@ type lowerFileContext struct {
668
669
  importAliases map[string]string
669
670
  importPaths map[string]string
670
671
  importNames map[string]string
672
+ importObjects map[*types.PkgName]string
671
673
  sourcePath string
672
674
  localAliases map[types.Object]string
673
675
  lazyPackageVars map[types.Object]bool
674
676
  identAliases map[types.Object]string
677
+ identAliasRefs map[types.Object]bool
675
678
  tempNames *tempNameOwner
676
679
  signature *types.Signature
680
+ typeParams map[string]bool
681
+ staticTypeParams map[string]bool
677
682
  asyncFunction bool
678
683
  functionTypeDepth int
679
684
  deferState *loweredDeferState
@@ -694,6 +699,30 @@ type tempNameOwner struct {
694
699
  counters map[string]int
695
700
  }
696
701
 
702
+ func (ctx lowerFileContext) canReferenceNamedType(named *types.Named) bool {
703
+ if named == nil || named.Obj() == nil {
704
+ return true
705
+ }
706
+ return ctx.canReferenceObjectPackage(named.Obj())
707
+ }
708
+
709
+ func (ctx lowerFileContext) canReferenceObjectPackage(obj types.Object) bool {
710
+ if obj == nil || obj.Pkg() == nil || ctx.semPkg == nil {
711
+ return true
712
+ }
713
+ pkgPath := obj.Pkg().Path()
714
+ if pkgPath == "" || pkgPath == ctx.semPkg.pkgPath {
715
+ return true
716
+ }
717
+ if ctx.importPaths[pkgPath] != "" {
718
+ return true
719
+ }
720
+ if ctx.localAliases[obj] != "" {
721
+ return true
722
+ }
723
+ return false
724
+ }
725
+
697
726
  func newTempNameOwner() *tempNameOwner {
698
727
  return &tempNameOwner{counters: make(map[string]int)}
699
728
  }
@@ -720,6 +749,20 @@ func (ctx lowerFileContext) withIdentAliases(aliases map[types.Object]string) lo
720
749
  return ctx
721
750
  }
722
751
 
752
+ func (ctx lowerFileContext) withIdentRefAliases(aliases map[types.Object]string) lowerFileContext {
753
+ if len(aliases) == 0 {
754
+ return ctx
755
+ }
756
+ ctx = ctx.withIdentAliases(aliases)
757
+ refs := make(map[types.Object]bool, len(ctx.identAliasRefs)+len(aliases))
758
+ maps.Copy(refs, ctx.identAliasRefs)
759
+ for obj := range aliases {
760
+ refs[obj] = true
761
+ }
762
+ ctx.identAliasRefs = refs
763
+ return ctx
764
+ }
765
+
723
766
  func (o *tempNameOwner) next(prefix string) string {
724
767
  idx := o.counters[prefix]
725
768
  o.counters[prefix] = idx + 1
@@ -838,9 +881,21 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
838
881
  decls = append(decls, loweredDecl{code: code, indexExport: indexExport})
839
882
  if lazy {
840
883
  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}"
884
+ getterCode := "export function " + getterName + "(): " + variableType + " {\n\t"
885
+ if strings.Contains(value, "await ") {
886
+ initName := packageVarInitName(name.Name)
887
+ initCode := "async function " + initName + "(): globalThis.Promise<void> {\n\t" +
888
+ "if (((" + declName + ") as any) === undefined) {\n\t\t" +
889
+ declName + " = " + value + "\n\t}\n}"
890
+ decls = append(decls, loweredDecl{code: initCode})
891
+ decls = append(decls, loweredDecl{packageInitCall: initName + "()"})
892
+ getterCode += "if (((" + declName + ") as any) === undefined) {\n\t\t" +
893
+ "throw new Error(" + strconv.Quote("goscript package variable "+name.Name+" read before initialization") + ")\n\t}\n"
894
+ } else {
895
+ getterCode += "if (((" + declName + ") as any) === undefined) {\n\t\t" +
896
+ declName + " = " + value + "\n\t}\n"
897
+ }
898
+ getterCode += "\treturn " + declName + "\n}"
844
899
  getterIndexExport := ""
845
900
  if ast.IsExported(name.Name) {
846
901
  getterIndexExport = getterName
@@ -924,7 +979,7 @@ func initializerMayHaveRuntimeEffects(ctx lowerFileContext, expr ast.Expr) bool
924
979
  return hasEffects
925
980
  }
926
981
 
927
- func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage) map[types.Object]bool {
982
+ func packageDeclFiles(semPkg *semanticPackage) map[types.Object]string {
928
983
  if semPkg == nil || semPkg.source == nil {
929
984
  return nil
930
985
  }
@@ -934,6 +989,25 @@ func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage) map[types.Objec
934
989
  declFiles[decl.object] = decl.position.file
935
990
  }
936
991
  }
992
+ return declFiles
993
+ }
994
+
995
+ func packageOutputNames(semPkg *semanticPackage) map[string]string {
996
+ if semPkg == nil || semPkg.source == nil {
997
+ return nil
998
+ }
999
+ outputNames := make(map[string]string, len(semPkg.source.Syntax))
1000
+ for idx, syntax := range semPkg.source.Syntax {
1001
+ outputSourcePath := sourceFilePath(semPkg, idx, syntax)
1002
+ outputNames[outputSourcePath] = sourceOutputName(outputSourcePath)
1003
+ }
1004
+ return outputNames
1005
+ }
1006
+
1007
+ func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage, declFiles map[types.Object]string) map[types.Object]bool {
1008
+ if semPkg == nil || semPkg.source == nil {
1009
+ return nil
1010
+ }
937
1011
  varOrder := make(map[types.Object]int)
938
1012
  for idx, obj := range semPkg.initOrder {
939
1013
  varOrder[obj] = idx
@@ -956,6 +1030,11 @@ func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage) map[types.Objec
956
1030
  if obj == nil {
957
1031
  continue
958
1032
  }
1033
+ if valueIdx < len(valueSpec.Values) &&
1034
+ initializerReferencesLaterPackageVar(semPkg, varOrder, obj, valueSpec.Values[valueIdx]) {
1035
+ lazy[obj] = true
1036
+ continue
1037
+ }
959
1038
  if valueIdx < len(valueSpec.Values) &&
960
1039
  initializerReferencesOtherFileObject(semPkg, declFiles, sourcePath, valueSpec.Values[valueIdx]) {
961
1040
  lazy[obj] = true
@@ -977,6 +1056,41 @@ func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage) map[types.Objec
977
1056
  return lazy
978
1057
  }
979
1058
 
1059
+ func initializerReferencesLaterPackageVar(
1060
+ semPkg *semanticPackage,
1061
+ varOrder map[types.Object]int,
1062
+ current types.Object,
1063
+ expr ast.Expr,
1064
+ ) bool {
1065
+ currentIdx, ok := varOrder[current]
1066
+ if !ok {
1067
+ return false
1068
+ }
1069
+ references := false
1070
+ ast.Inspect(expr, func(node ast.Node) bool {
1071
+ if references {
1072
+ return false
1073
+ }
1074
+ if _, ok := node.(*ast.FuncLit); ok {
1075
+ return false
1076
+ }
1077
+ ident, ok := node.(*ast.Ident)
1078
+ if !ok {
1079
+ return true
1080
+ }
1081
+ obj, ok := semPkg.source.TypesInfo.Uses[ident].(*types.Var)
1082
+ if !ok || obj.Pkg() == nil || obj.Pkg().Path() != semPkg.pkgPath {
1083
+ return true
1084
+ }
1085
+ if idx, ok := varOrder[obj]; ok && idx > currentIdx {
1086
+ references = true
1087
+ return false
1088
+ }
1089
+ return true
1090
+ })
1091
+ return references
1092
+ }
1093
+
980
1094
  func initializerCallsFunctionReferencingLaterPackageVar(
981
1095
  semPkg *semanticPackage,
982
1096
  varOrder map[types.Object]int,
@@ -1223,7 +1337,7 @@ func lowerConstantValue(value constant.Value) (string, bool) {
1223
1337
  case constant.Bool:
1224
1338
  return strconv.FormatBool(constant.BoolVal(value)), true
1225
1339
  case constant.String:
1226
- return strconv.Quote(constant.StringVal(value)), true
1340
+ return lowerGoStringLiteral(constant.StringVal(value)), true
1227
1341
  case constant.Int:
1228
1342
  if intValue, ok := constant.Int64Val(value); ok {
1229
1343
  return strconv.FormatInt(intValue, 10), true
@@ -1237,7 +1351,7 @@ func lowerConstantValue(value constant.Value) (string, bool) {
1237
1351
  case constant.Complex:
1238
1352
  real := constant.Real(value).ExactString()
1239
1353
  imag := constant.Imag(value).ExactString()
1240
- return "({ real: " + real + ", imag: " + imag + " })", true
1354
+ return "$.complex(" + real + ", " + imag + ")", true
1241
1355
  default:
1242
1356
  return "", false
1243
1357
  }
@@ -1333,6 +1447,13 @@ func byteSliceLiteral(data []byte) string {
1333
1447
  return "new Uint8Array([" + strings.Join(values, ", ") + "])"
1334
1448
  }
1335
1449
 
1450
+ func lowerGoStringLiteral(value string) string {
1451
+ if utf8.ValidString(value) {
1452
+ return strconv.Quote(value)
1453
+ }
1454
+ return "$.bytesToString(" + byteSliceLiteral([]byte(value)) + ")"
1455
+ }
1456
+
1336
1457
  func (o *LoweringOwner) lowerTypeSpec(ctx lowerFileContext, spec *ast.TypeSpec) (loweredDecl, []Diagnostic) {
1337
1458
  obj, _ := ctx.semPkg.source.TypesInfo.Defs[spec.Name].(*types.TypeName)
1338
1459
  if obj == nil {
@@ -1396,7 +1517,7 @@ func (o *LoweringOwner) lowerInterfaceType(ctx lowerFileContext, semType *semant
1396
1517
  code = code + "\n\n" + o.runtimeOwner.QualifiedHelper(RuntimeHelperRegisterInterfaceType) +
1397
1518
  "(\n\t" + strconv.Quote(runtimeNamedTypeName(semType.named)) +
1398
1519
  ",\n\tnull,\n\t" + o.runtimeMethodSignatures(iface) + "\n)"
1399
- return loweredDecl{code: code, typeIndexExport: typeIndexExport}
1520
+ return loweredDecl{code: code, typeIndexExport: typeIndexExport, sideEffect: true}
1400
1521
  }
1401
1522
 
1402
1523
  func (o *LoweringOwner) tsInterfaceType(ctx lowerFileContext, iface *types.Interface) string {
@@ -1407,7 +1528,7 @@ func (o *LoweringOwner) tsInterfaceType(ctx lowerFileContext, iface *types.Inter
1407
1528
  for method := range iface.Methods() {
1408
1529
  methods = append(methods, o.tsMethodSignature(ctx, method))
1409
1530
  }
1410
- return "null | {\n\t" + strings.Join(methods, "\n\t") + "\n}"
1531
+ return "{\n\t" + strings.Join(methods, "\n\t") + "\n}"
1411
1532
  }
1412
1533
 
1413
1534
  func (o *LoweringOwner) tsMethodSignature(ctx lowerFileContext, method *types.Func) string {
@@ -1417,7 +1538,7 @@ func (o *LoweringOwner) tsMethodSignature(ctx lowerFileContext, method *types.Fu
1417
1538
  }
1418
1539
  async := o.functionAsync(ctx, method)
1419
1540
  return method.Name() + "(" + o.tsSignatureParamsFor(ctx, signature, async) + "): " +
1420
- asyncResultType(o.tsSignatureResultFor(ctx, signature), async)
1541
+ asyncCompatibleMethodResultType(o.tsSignatureResultFor(ctx, signature), async)
1421
1542
  }
1422
1543
 
1423
1544
  func (o *LoweringOwner) runtimeMethodSignatures(iface *types.Interface) string {
@@ -1483,6 +1604,10 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
1483
1604
  cloneMethod: "clone",
1484
1605
  }
1485
1606
  for idx, field := range semType.fields {
1607
+ structValue := isStructValueType(field.typ)
1608
+ if named := namedStructType(field.typ); named != nil && crossPackageUnexportedNamedType(ctx, named) {
1609
+ structValue = false
1610
+ }
1486
1611
  fieldName := tsStructFieldName(field.name, idx)
1487
1612
  runtimeName := ""
1488
1613
  if fieldName != field.name {
@@ -1496,11 +1621,18 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
1496
1621
  runtimeType: o.runtimeTypeInfoExpr(field.typ),
1497
1622
  doc: field.doc,
1498
1623
  tag: field.tag,
1499
- structValue: isStructValueType(field.typ),
1624
+ structValue: structValue,
1625
+ arrayValue: isArrayType(field.typ),
1500
1626
  })
1501
1627
  }
1502
1628
 
1503
1629
  methodDecls := o.methodDeclsForType(ctx, semType.named)
1630
+ explicitMethods := make(map[string]bool, len(methodDecls))
1631
+ for _, methodDecl := range methodDecls {
1632
+ if methodDecl != nil {
1633
+ explicitMethods[methodDecl.Name.Name] = true
1634
+ }
1635
+ }
1504
1636
  var diagnostics []Diagnostic
1505
1637
  for _, methodDecl := range methodDecls {
1506
1638
  method, methodDiagnostics := o.lowerFuncDecl(ctx, methodDecl)
@@ -1512,9 +1644,121 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
1512
1644
  lowered.methods = append(lowered.methods, *method)
1513
1645
  }
1514
1646
  }
1647
+ for _, field := range semType.fields {
1648
+ methods := o.lowerEmbeddedMethodForwarders(ctx, field, explicitMethods)
1649
+ lowered.methods = append(lowered.methods, methods...)
1650
+ }
1515
1651
  return lowered, diagnostics
1516
1652
  }
1517
1653
 
1654
+ func (o *LoweringOwner) lowerEmbeddedMethodForwarders(
1655
+ ctx lowerFileContext,
1656
+ field semanticField,
1657
+ explicitMethods map[string]bool,
1658
+ ) []loweredFunction {
1659
+ if !field.embedded {
1660
+ return nil
1661
+ }
1662
+ methodSetType := field.typ
1663
+ if named := namedStructType(field.typ); named != nil {
1664
+ methodSetType = types.NewPointer(field.typ)
1665
+ } else if pointerToNamedStructType(field.typ) != nil {
1666
+ methodSetType = field.typ
1667
+ } else if _, ok := types.Unalias(field.typ).Underlying().(*types.Interface); !ok {
1668
+ return nil
1669
+ }
1670
+ methodSet := types.NewMethodSet(methodSetType)
1671
+ if methodSet.Len() == 0 {
1672
+ return nil
1673
+ }
1674
+ var methods []loweredFunction
1675
+ for selection := range methodSet.Methods() {
1676
+ method, _ := selection.Obj().(*types.Func)
1677
+ if method == nil || explicitMethods[method.Name()] {
1678
+ continue
1679
+ }
1680
+ if !ast.IsExported(method.Name()) && method.Pkg() != nil && method.Pkg().Path() != ctx.semPkg.pkgPath {
1681
+ continue
1682
+ }
1683
+ signature, _ := method.Type().(*types.Signature)
1684
+ if signature == nil {
1685
+ continue
1686
+ }
1687
+ async := o.functionAsync(ctx, method)
1688
+ targetType := o.tsEmbeddedForwarderTargetType(ctx, field.typ)
1689
+ lowered := loweredFunction{
1690
+ async: async,
1691
+ name: methodMemberName(method.Name()),
1692
+ runtimeName: method.Name(),
1693
+ result: asyncResultType("any", async),
1694
+ deferState: &loweredDeferState{},
1695
+ }
1696
+ args := make([]string, 0, signature.Params().Len())
1697
+ for idx := range signature.Params().Len() {
1698
+ param := signature.Params().At(idx)
1699
+ name := safeParamName(param, idx)
1700
+ args = append(args, name)
1701
+ lowered.params = append(lowered.params, loweredParam{name: name, typ: "any"})
1702
+ }
1703
+ target := o.embeddedForwarderTargetExpr(ctx, field, selection, targetType)
1704
+ call := target + "." + method.Name() + "(" + strings.Join(args, ", ") + ")"
1705
+ if async {
1706
+ call = "await " + call
1707
+ }
1708
+ lowered.body = []loweredStmt{{text: "return " + call}}
1709
+ methods = append(methods, lowered)
1710
+ explicitMethods[method.Name()] = true
1711
+ }
1712
+ return methods
1713
+ }
1714
+
1715
+ func (o *LoweringOwner) embeddedForwarderTargetExpr(
1716
+ ctx lowerFileContext,
1717
+ field semanticField,
1718
+ selection *types.Selection,
1719
+ targetType string,
1720
+ ) string {
1721
+ pointerValue := o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue)
1722
+ expr := pointerValue + "<" + targetType + ">(this." + tsStructFieldName(field.name, 0) + ")"
1723
+ if selection == nil || len(selection.Index()) <= 1 {
1724
+ return expr
1725
+ }
1726
+
1727
+ typ := field.typ
1728
+ for _, index := range selection.Index()[:len(selection.Index())-1] {
1729
+ structType, ok := types.Unalias(derefPointerType(typ)).Underlying().(*types.Struct)
1730
+ if !ok || index < 0 || index >= structType.NumFields() {
1731
+ return expr
1732
+ }
1733
+ field := structType.Field(index)
1734
+ expr += "." + tsStructFieldName(field.Name(), index)
1735
+ typ = field.Type()
1736
+ expr = o.embeddedForwarderSelectableExpr(ctx, typ, expr)
1737
+ }
1738
+ return expr
1739
+ }
1740
+
1741
+ func (o *LoweringOwner) embeddedForwarderSelectableExpr(ctx lowerFileContext, typ types.Type, expr string) string {
1742
+ pointerValue := o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue)
1743
+ if named := pointerToNamedStructType(typ); named != nil {
1744
+ return pointerValue + "<any>(" + expr + ")"
1745
+ }
1746
+ if _, ok := types.Unalias(typ).Underlying().(*types.Interface); ok {
1747
+ return pointerValue + "<any>(" + expr + ")"
1748
+ }
1749
+ return expr
1750
+ }
1751
+
1752
+ func (o *LoweringOwner) tsEmbeddedForwarderTargetType(ctx lowerFileContext, typ types.Type) string {
1753
+ if named := pointerToNamedStructType(typ); named != nil {
1754
+ return o.namedTypeExpr(ctx, named)
1755
+ }
1756
+ if named := namedStructType(typ); named != nil {
1757
+ return o.namedTypeExpr(ctx, named)
1758
+ }
1759
+ return "Exclude<" + o.tsStructFieldTypeFor(ctx, typ) + ", null>"
1760
+ }
1761
+
1518
1762
  func (o *LoweringOwner) methodDeclsForType(ctx lowerFileContext, named *types.Named) []*ast.FuncDecl {
1519
1763
  if named == nil {
1520
1764
  return nil
@@ -1574,7 +1818,8 @@ func (o *LoweringOwner) lowerNamedReceiverMethodDecl(
1574
1818
  return nil, nil
1575
1819
  }
1576
1820
  async := o.functionAsync(ctx, fnObj)
1577
- resultCtx := ctx.withAsyncFunction(async)
1821
+ functionCtx := ctx.withSignature(signature)
1822
+ resultCtx := functionCtx.withAsyncFunction(async)
1578
1823
  result := o.tsSignatureResultFor(resultCtx, signature)
1579
1824
  receiverName := "recv"
1580
1825
  if len(decl.Recv.List) != 0 && len(decl.Recv.List[0].Names) != 0 {
@@ -1634,7 +1879,11 @@ func (o *LoweringOwner) lowerFuncDecl(ctx lowerFileContext, decl *ast.FuncDecl)
1634
1879
  return nil, nil
1635
1880
  }
1636
1881
  async := o.functionAsync(ctx, fnObj)
1637
- resultCtx := ctx.withAsyncFunction(async)
1882
+ if decl.Name.Name == "main" {
1883
+ async = true
1884
+ }
1885
+ functionCtx := ctx.withSignature(signature)
1886
+ resultCtx := functionCtx.withAsyncFunction(async)
1638
1887
  result := o.tsSignatureResultFor(resultCtx, signature)
1639
1888
  deferState := &loweredDeferState{}
1640
1889
  name := safeIdentifier(decl.Name.Name)
@@ -1659,9 +1908,10 @@ func (o *LoweringOwner) lowerFuncDecl(ctx lowerFileContext, decl *ast.FuncDecl)
1659
1908
  runtimeName: runtimeName,
1660
1909
  result: asyncResultType(result, async),
1661
1910
  deferState: deferState,
1662
- namedResults: o.lowerNamedResults(ctx, signature),
1911
+ namedResults: o.lowerNamedResults(functionCtx, signature),
1663
1912
  }
1664
1913
  if signature.TypeParams() != nil && signature.TypeParams().Len() != 0 {
1914
+ lowered.typeParams = signatureTypeParamNames(signature)
1665
1915
  lowered.params = append(lowered.params, loweredParam{
1666
1916
  name: "__typeArgs",
1667
1917
  typ: "$.GenericTypeArgs | undefined",
@@ -1684,24 +1934,20 @@ func (o *LoweringOwner) lowerFuncDecl(ctx lowerFileContext, decl *ast.FuncDecl)
1684
1934
  lowered.receiverValue = o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(this)"
1685
1935
  }
1686
1936
  }
1687
- if decl.Name.Name == "main" {
1688
- lowered.async = true
1689
- lowered.result = asyncResultType(o.tsSignatureResultFor(ctx.withAsyncFunction(true), signature), true)
1690
- }
1691
1937
  for idx := range signature.Params().Len() {
1692
1938
  param := signature.Params().At(idx)
1693
- lowered.params, lowered.paramBindings = o.appendLoweredParam(ctx, lowered.params, lowered.paramBindings, param, idx, decl.Body == nil || async)
1939
+ lowered.params, lowered.paramBindings = o.appendLoweredParam(functionCtx, lowered.params, lowered.paramBindings, param, idx, decl.Body == nil || async)
1694
1940
  }
1695
1941
  if decl.Body != nil {
1696
- body, diagnostics := o.lowerBlock(ctx.withSignature(signature).withAsyncFunction(async).withDeferState(deferState), decl.Body)
1942
+ body, diagnostics := o.lowerBlock(functionCtx.withAsyncFunction(async).withDeferState(deferState), decl.Body)
1697
1943
  lowered.body = body
1698
1944
  if deferState.async && !lowered.async {
1699
1945
  lowered.async = true
1700
- lowered.result = asyncResultType(o.tsSignatureResultFor(ctx.withAsyncFunction(true), signature), true)
1946
+ lowered.result = asyncResultType(o.tsSignatureResultFor(functionCtx.withAsyncFunction(true), signature), true)
1701
1947
  }
1702
1948
  return lowered, diagnostics
1703
1949
  }
1704
- if zeroReturn, ok := o.lowerBodylessReturnStmt(ctx, signature); ok {
1950
+ if zeroReturn, ok := o.lowerBodylessReturnStmt(functionCtx, signature); ok {
1705
1951
  lowered.body = []loweredStmt{{text: zeroReturn}}
1706
1952
  }
1707
1953
  return lowered, nil
@@ -1754,6 +2000,54 @@ func rangeBindingAssignedInBody(ctx lowerFileContext, expr ast.Expr, body *ast.B
1754
2000
  return objectAssignedInBlock(ctx, obj, body)
1755
2001
  }
1756
2002
 
2003
+ func (o *LoweringOwner) lowerMapRangeBinding(
2004
+ ctx lowerFileContext,
2005
+ expr ast.Expr,
2006
+ name string,
2007
+ fallback string,
2008
+ tempPrefix string,
2009
+ declare bool,
2010
+ ) (string, []loweredStmt, []Diagnostic) {
2011
+ if expr == nil {
2012
+ return fallback, nil, nil
2013
+ }
2014
+ if ident, ok := expr.(*ast.Ident); ok && ident.Name == "_" {
2015
+ return fallback, nil, nil
2016
+ }
2017
+ if declare {
2018
+ obj := rangeBindingObject(ctx, expr)
2019
+ if name == "" || obj == nil || !ctx.model.needsVarRef[obj] {
2020
+ if name != "" {
2021
+ return name, nil, nil
2022
+ }
2023
+ return fallback, nil, nil
2024
+ }
2025
+ rawName := ctx.tempName(tempPrefix)
2026
+ value := rawName
2027
+ if isStructValueType(obj.Type()) {
2028
+ value = o.lowerStructClone(value)
2029
+ }
2030
+ return rawName, []loweredStmt{{
2031
+ text: "let " + name + ": " + o.tsVariableTypeFor(ctx, obj.Type(), true) + " = " +
2032
+ o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(" + value + ")",
2033
+ }}, nil
2034
+ }
2035
+ rawName := ctx.tempName(tempPrefix)
2036
+ left, diagnostics := o.lowerAssignmentTarget(ctx, expr, false)
2037
+ return rawName, []loweredStmt{{text: left + " = " + rawName}}, diagnostics
2038
+ }
2039
+
2040
+ func rangeBindingObject(ctx lowerFileContext, expr ast.Expr) types.Object {
2041
+ ident, ok := expr.(*ast.Ident)
2042
+ if !ok || ident.Name == "_" || ctx.semPkg == nil || ctx.semPkg.source == nil {
2043
+ return nil
2044
+ }
2045
+ if obj := ctx.semPkg.source.TypesInfo.Defs[ident]; obj != nil {
2046
+ return obj
2047
+ }
2048
+ return ctx.semPkg.source.TypesInfo.Uses[ident]
2049
+ }
2050
+
1757
2051
  func expressionUsesObject(ctx lowerFileContext, expr ast.Expr, obj types.Object) bool {
1758
2052
  if expr == nil || obj == nil || ctx.semPkg == nil || ctx.semPkg.source == nil {
1759
2053
  return false
@@ -1803,6 +2097,20 @@ func (o *LoweringOwner) appendLoweredParam(
1803
2097
 
1804
2098
  func (ctx lowerFileContext) withSignature(signature *types.Signature) lowerFileContext {
1805
2099
  ctx.signature = signature
2100
+ if signature != nil && signature.TypeParams() != nil && signature.TypeParams().Len() != 0 {
2101
+ next := make(map[string]bool, len(ctx.typeParams)+signature.TypeParams().Len())
2102
+ maps.Copy(next, ctx.typeParams)
2103
+ nextStatic := make(map[string]bool, len(ctx.staticTypeParams)+signature.TypeParams().Len())
2104
+ maps.Copy(nextStatic, ctx.staticTypeParams)
2105
+ for typeParam := range signature.TypeParams().TypeParams() {
2106
+ next[typeParam.Obj().Name()] = true
2107
+ if signatureUsesTypeParamAsSliceElem(signature, typeParam) {
2108
+ nextStatic[typeParam.Obj().Name()] = true
2109
+ }
2110
+ }
2111
+ ctx.typeParams = next
2112
+ ctx.staticTypeParams = nextStatic
2113
+ }
1806
2114
  return ctx
1807
2115
  }
1808
2116
 
@@ -1852,7 +2160,18 @@ func (ctx lowerFileContext) withoutRangeBreak() lowerFileContext {
1852
2160
  }
1853
2161
 
1854
2162
  func (ctx lowerFileContext) withGotoLabels(labels map[string]bool) lowerFileContext {
1855
- ctx.gotoLabels = labels
2163
+ if len(ctx.gotoLabels) == 0 {
2164
+ ctx.gotoLabels = labels
2165
+ return ctx
2166
+ }
2167
+ merged := make(map[string]bool, len(ctx.gotoLabels)+len(labels))
2168
+ for label := range ctx.gotoLabels {
2169
+ merged[label] = true
2170
+ }
2171
+ for label := range labels {
2172
+ merged[label] = true
2173
+ }
2174
+ ctx.gotoLabels = merged
1856
2175
  return ctx
1857
2176
  }
1858
2177
 
@@ -1884,6 +2203,11 @@ func (ctx lowerFileContext) withLoopLabel(label string) lowerFileContext {
1884
2203
  return ctx
1885
2204
  }
1886
2205
 
2206
+ func (ctx lowerFileContext) withoutLoopLabel() lowerFileContext {
2207
+ ctx.loopLabel = ""
2208
+ return ctx
2209
+ }
2210
+
1887
2211
  func (ctx lowerFileContext) withSwitchBreak() lowerFileContext {
1888
2212
  ctx.switchBreak = true
1889
2213
  return ctx
@@ -1999,6 +2323,22 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
1999
2323
  expr, diagnostics := o.lowerPointerStorageExpr(ctx, star.X)
2000
2324
  return []loweredStmt{{text: expr + typed.Tok.String()}}, diagnostics
2001
2325
  }
2326
+ if index, ok := unwrapParenExpr(typed.X).(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) {
2327
+ right := "1"
2328
+ tok := token.ADD_ASSIGN
2329
+ if typed.Tok == token.DEC {
2330
+ tok = token.SUB_ASSIGN
2331
+ }
2332
+ return o.lowerMapIndexUpdateStmts(ctx, index, tok, right, ctx.semPkg.source.TypesInfo.TypeOf(typed.X))
2333
+ }
2334
+ if setter, ok := o.packageVarSetterForAssignment(ctx, typed.X); ok {
2335
+ expr, diagnostics := o.lowerExpr(ctx, typed.X)
2336
+ op := "+"
2337
+ if typed.Tok == token.DEC {
2338
+ op = "-"
2339
+ }
2340
+ return []loweredStmt{{text: setter + "(" + expr + " " + op + " 1)"}}, diagnostics
2341
+ }
2002
2342
  expr, diagnostics := o.lowerExpr(ctx, typed.X)
2003
2343
  return []loweredStmt{{text: expr + typed.Tok.String()}}, diagnostics
2004
2344
  case *ast.BranchStmt:
@@ -2068,6 +2408,10 @@ func packageVarGetterName(name string) string {
2068
2408
  return "__goscript_get_" + safeIdentifier(name)
2069
2409
  }
2070
2410
 
2411
+ func packageVarInitName(name string) string {
2412
+ return "__goscript_init_" + safeIdentifier(name)
2413
+ }
2414
+
2071
2415
  func (o *LoweringOwner) lowerElse(ctx lowerFileContext, stmt ast.Stmt) ([]loweredStmt, []Diagnostic) {
2072
2416
  switch typed := stmt.(type) {
2073
2417
  case *ast.BlockStmt:
@@ -2190,6 +2534,19 @@ func (o *LoweringOwner) lowerStmtListAfter(
2190
2534
  continue
2191
2535
  }
2192
2536
  }
2537
+ if stmtCtx, nextCtx, ok := o.lowerDeclStatementContext(ctx, stmt); ok {
2538
+ stmtLowered, stmtDiagnostics := o.lowerStmt(stmtCtx, stmt)
2539
+ diagnostics = append(diagnostics, stmtDiagnostics...)
2540
+ if len(stmtLowered) != 0 && len(leading) != 0 {
2541
+ stmtLowered[0].leading = append(leading, stmtLowered[0].leading...)
2542
+ }
2543
+ lowered = append(lowered, stmtLowered...)
2544
+ ctx = nextCtx
2545
+ if endLine := sourceLine(ctx, stmt.End()); endLine != 0 {
2546
+ prevEndLine = endLine
2547
+ }
2548
+ continue
2549
+ }
2193
2550
  if stmtCtx, nextCtx, prelude, ok := o.lowerShortDeclStatementContext(ctx, stmt); ok {
2194
2551
  stmtLowered, stmtDiagnostics := o.lowerStmt(stmtCtx, stmt)
2195
2552
  diagnostics = append(diagnostics, stmtDiagnostics...)
@@ -2221,23 +2578,61 @@ func (o *LoweringOwner) lowerStmtListAfter(
2221
2578
  return lowered, diagnostics
2222
2579
  }
2223
2580
 
2224
- type gotoStateCluster struct {
2225
- startIdx int
2226
- firstLabelIdx int
2227
- endIdx int
2228
- labels []gotoStateLabel
2229
- }
2230
-
2231
- type gotoStateLabel struct {
2232
- name string
2233
- idx int
2234
- }
2235
-
2236
- func gotoStateClusterAt(stmts []ast.Stmt, idx int) (gotoStateCluster, bool) {
2237
- labelIndexes := make(map[string]int)
2238
- for stmtIdx, stmt := range stmts {
2239
- labeled, ok := stmt.(*ast.LabeledStmt)
2240
- if !ok {
2581
+ func (o *LoweringOwner) lowerDeclStatementContext(
2582
+ ctx lowerFileContext,
2583
+ stmt ast.Stmt,
2584
+ ) (lowerFileContext, lowerFileContext, bool) {
2585
+ declStmt, ok := stmt.(*ast.DeclStmt)
2586
+ if !ok {
2587
+ return ctx, ctx, false
2588
+ }
2589
+ genDecl, ok := declStmt.Decl.(*ast.GenDecl)
2590
+ if !ok || genDecl.Tok != token.VAR {
2591
+ return ctx, ctx, false
2592
+ }
2593
+ aliases := make(map[types.Object]string)
2594
+ for _, spec := range genDecl.Specs {
2595
+ valueSpec, ok := spec.(*ast.ValueSpec)
2596
+ if !ok {
2597
+ continue
2598
+ }
2599
+ for _, name := range valueSpec.Names {
2600
+ if name.Name == "_" {
2601
+ continue
2602
+ }
2603
+ def := ctx.semPkg.source.TypesInfo.Defs[name]
2604
+ if def == nil || aliases[def] != "" {
2605
+ continue
2606
+ }
2607
+ if shortDeclDefShadowsOuterName(name.Name, def) {
2608
+ aliases[def] = ctx.tempName("Shadow")
2609
+ }
2610
+ }
2611
+ }
2612
+ if len(aliases) == 0 {
2613
+ return ctx, ctx, false
2614
+ }
2615
+ nextCtx := ctx.withIdentRefAliases(aliases)
2616
+ return nextCtx, nextCtx, true
2617
+ }
2618
+
2619
+ type gotoStateCluster struct {
2620
+ startIdx int
2621
+ firstLabelIdx int
2622
+ endIdx int
2623
+ labels []gotoStateLabel
2624
+ }
2625
+
2626
+ type gotoStateLabel struct {
2627
+ name string
2628
+ idx int
2629
+ }
2630
+
2631
+ func gotoStateClusterAt(stmts []ast.Stmt, idx int) (gotoStateCluster, bool) {
2632
+ labelIndexes := make(map[string]int)
2633
+ for stmtIdx, stmt := range stmts {
2634
+ labeled, ok := stmt.(*ast.LabeledStmt)
2635
+ if !ok {
2241
2636
  continue
2242
2637
  }
2243
2638
  labelIndexes[safeIdentifier(labeled.Label.Name)] = stmtIdx
@@ -2387,10 +2782,8 @@ func (o *LoweringOwner) lowerShortDeclStatementContext(
2387
2782
  if len(oldAliases) == 0 && len(newAliases) == 0 {
2388
2783
  return ctx, ctx, nil, false
2389
2784
  }
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
2785
+ stmtCtx := ctx.withIdentAliases(oldAliases).withIdentRefAliases(newAliases)
2786
+ return stmtCtx, ctx.withIdentRefAliases(newAliases), prelude, true
2394
2787
  }
2395
2788
 
2396
2789
  func (o *LoweringOwner) lowerBackwardGotoLoop(
@@ -2605,6 +2998,9 @@ func (o *LoweringOwner) lowerSendStmt(ctx lowerFileContext, stmt *ast.SendStmt)
2605
2998
  channel, channelDiagnostics := o.lowerExpr(ctx, stmt.Chan)
2606
2999
  value, valueDiagnostics := o.lowerExpr(ctx, stmt.Value)
2607
3000
  diagnostics := append(channelDiagnostics, valueDiagnostics...)
3001
+ if channelType, _ := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(stmt.Chan)).Underlying().(*types.Chan); channelType != nil {
3002
+ value = o.lowerValueForTarget(ctx, stmt.Value, channelType.Elem(), value)
3003
+ }
2608
3004
  return "await " + o.runtimeOwner.QualifiedHelper(RuntimeHelperChanSend) + "(" + channel + ", " + value + ")", diagnostics
2609
3005
  }
2610
3006
 
@@ -2616,6 +3012,25 @@ func (o *LoweringOwner) lowerGoStmt(ctx lowerFileContext, stmt *ast.GoStmt) (str
2616
3012
  }
2617
3013
 
2618
3014
  func (o *LoweringOwner) lowerDeferStmt(ctx lowerFileContext, stmt *ast.DeferStmt) (string, []Diagnostic) {
3015
+ if nestedCall, ok := stmt.Call.Fun.(*ast.CallExpr); ok {
3016
+ callee, diagnostics := o.lowerCallExpr(ctx, nestedCall)
3017
+ args, argDiagnostics := o.lowerCallArgs(ctx, stmt.Call, callTargetSignature(ctx, stmt.Call.Fun))
3018
+ diagnostics = append(diagnostics, argDiagnostics...)
3019
+ calleeTemp := ctx.tempName("DeferCallee")
3020
+ call := o.lowerCallableExpr(ctx, stmt.Call.Fun, calleeTemp) + "(" + strings.Join(args, ", ") + ")"
3021
+ call = o.awaitCallIfNeeded(ctx, stmt.Call.Fun, call)
3022
+ async := strings.Contains(callee, "await ") || strings.Contains(call, "await ")
3023
+ if ctx.deferState != nil {
3024
+ ctx.deferState.used = true
3025
+ if async {
3026
+ ctx.deferState.async = true
3027
+ }
3028
+ }
3029
+ if async {
3030
+ return "const " + calleeTemp + " = " + callee + "\n__defer.defer(async () => { " + call + " })", diagnostics
3031
+ }
3032
+ return "const " + calleeTemp + " = " + callee + "\n__defer.defer(() => { " + call + " })", diagnostics
3033
+ }
2619
3034
  call, diagnostics := o.lowerCallExpr(ctx, stmt.Call)
2620
3035
  async := strings.Contains(call, "await ")
2621
3036
  if ctx.deferState != nil {
@@ -2682,41 +3097,51 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
2682
3097
  isShortDecl := stmt.Tok == token.DEFINE && isShortAssignTargetNew(ctx, lhs)
2683
3098
  right, rightDiagnostics := o.lowerExpr(ctx, stmt.Rhs[idx])
2684
3099
  diagnostics = append(diagnostics, rightDiagnostics...)
2685
- targetType := ctx.semPkg.source.TypesInfo.TypeOf(lhs)
3100
+ targetType := assignmentTargetType(ctx, lhs)
2686
3101
  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 + ")"})
3102
+ if targetType != nil && genericCallResultUsesTypeParam(ctx, stmt.Rhs[idx]) {
3103
+ right = "(" + right + " as " + o.tsTypeFor(ctx, targetType) + ")"
3104
+ }
3105
+ if setter, ok := o.packageVarSetterForAssignment(ctx, lhs); ok {
3106
+ value, ok := o.packageVarAssignmentValue(ctx, lhs, targetType, right, stmt.Tok)
3107
+ if !ok {
3108
+ value = right
3109
+ }
3110
+ stmts = append(stmts, loweredStmt{text: setter + "(" + value + ")"})
2689
3111
  continue
2690
3112
  }
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 + ")"})
3113
+ if index, ok := lhs.(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) && stmt.Tok != token.DEFINE {
3114
+ update, updateDiagnostics := o.lowerMapIndexUpdateStmts(ctx, index, stmt.Tok, right, targetType)
3115
+ diagnostics = append(diagnostics, updateDiagnostics...)
3116
+ stmts = append(stmts, update...)
2699
3117
  continue
2700
3118
  }
2701
- if star, ok := lhs.(*ast.StarExpr); ok && stmt.Tok == token.ASSIGN && isStructValueType(targetType) {
3119
+ left, leftDiagnostics := o.lowerAssignmentTarget(ctx, lhs, isShortDecl)
3120
+ diagnostics = append(diagnostics, leftDiagnostics...)
3121
+ star, starTarget := unwrapParenExpr(lhs).(*ast.StarExpr)
3122
+ if starTarget && stmt.Tok == token.ASSIGN && isStructValueType(targetType) {
2702
3123
  pointer, pointerDiagnostics := o.lowerPointerValueExpr(ctx, star.X)
2703
3124
  diagnostics = append(diagnostics, pointerDiagnostics...)
2704
3125
  stmts = append(stmts, loweredStmt{text: o.runtimeOwner.QualifiedHelper(RuntimeHelperAssignStruct) + "(" + pointer + ", " + right + ")"})
2705
3126
  continue
2706
3127
  }
2707
- if star, ok := lhs.(*ast.StarExpr); ok && stmt.Tok == token.ASSIGN {
3128
+ if starTarget && stmt.Tok == token.ASSIGN {
2708
3129
  pointer, pointerDiagnostics := o.lowerPointerStorageExpr(ctx, star.X)
2709
3130
  diagnostics = append(diagnostics, pointerDiagnostics...)
2710
3131
  stmts = append(stmts, loweredStmt{text: pointer + " = " + right})
2711
3132
  continue
2712
3133
  }
2713
- if star, ok := lhs.(*ast.StarExpr); ok && stmt.Tok != token.DEFINE {
3134
+ if starTarget && stmt.Tok != token.DEFINE {
2714
3135
  pointer, pointerDiagnostics := o.lowerPointerStorageExpr(ctx, star.X)
2715
3136
  diagnostics = append(diagnostics, pointerDiagnostics...)
2716
3137
  if stmt.Tok == token.AND_NOT_ASSIGN {
2717
3138
  stmts = append(stmts, loweredStmt{text: pointer + " = " + pointer + " & ~(" + right + ")"})
2718
3139
  continue
2719
3140
  }
3141
+ if value, ok := integerQuotientAssignExpr(targetType, pointer, right, stmt.Tok); ok {
3142
+ stmts = append(stmts, loweredStmt{text: value})
3143
+ continue
3144
+ }
2720
3145
  stmts = append(stmts, loweredStmt{text: pointer + " " + stmt.Tok.String() + " " + right})
2721
3146
  continue
2722
3147
  }
@@ -2735,6 +3160,10 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
2735
3160
  stmts = append(stmts, loweredStmt{text: left + " = " + o.runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")"})
2736
3161
  continue
2737
3162
  }
3163
+ if value, ok := integerQuotientAssignExpr(targetType, left, right, stmt.Tok); ok {
3164
+ stmts = append(stmts, loweredStmt{text: value})
3165
+ continue
3166
+ }
2738
3167
  op := stmt.Tok.String()
2739
3168
  if stmt.Tok == token.DEFINE {
2740
3169
  op = "="
@@ -2744,6 +3173,98 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
2744
3173
  return stmts, diagnostics
2745
3174
  }
2746
3175
 
3176
+ func (o *LoweringOwner) lowerMapIndexUpdateStmts(
3177
+ ctx lowerFileContext,
3178
+ index *ast.IndexExpr,
3179
+ tok token.Token,
3180
+ right string,
3181
+ targetType types.Type,
3182
+ ) ([]loweredStmt, []Diagnostic) {
3183
+ mapExpr, mapDiagnostics := o.lowerExpr(ctx, index.X)
3184
+ keyExpr, keyDiagnostics := o.lowerExpr(ctx, index.Index)
3185
+ diagnostics := append(mapDiagnostics, keyDiagnostics...)
3186
+ if tok == token.ASSIGN {
3187
+ return []loweredStmt{{text: o.runtimeOwner.QualifiedHelper(RuntimeHelperMapSet) + "(" + mapExpr + ", " + keyExpr + ", " + right + ")"}}, diagnostics
3188
+ }
3189
+ mapTemp := ctx.tempName("Map")
3190
+ keyTemp := ctx.tempName("MapKey")
3191
+ current := o.lowerMapGetValue(ctx, index, mapTemp, keyTemp)
3192
+ value := lowerCompoundAssignValue(o.runtimeOwner, targetType, current, right, tok)
3193
+ return []loweredStmt{
3194
+ {text: "const " + mapTemp + " = " + mapExpr},
3195
+ {text: "const " + keyTemp + " = " + keyExpr},
3196
+ {text: o.runtimeOwner.QualifiedHelper(RuntimeHelperMapSet) + "(" + mapTemp + ", " + keyTemp + ", " + value + ")"},
3197
+ }, diagnostics
3198
+ }
3199
+
3200
+ func lowerCompoundAssignValue(
3201
+ runtimeOwner *RuntimeContractOwner,
3202
+ targetType types.Type,
3203
+ left string,
3204
+ right string,
3205
+ tok token.Token,
3206
+ ) string {
3207
+ if helper, ok := wideIntegerAssignHelper(targetType, tok); ok {
3208
+ return runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")"
3209
+ }
3210
+ if value, ok := integerQuotientAssignValueExpr(targetType, left, right, tok); ok {
3211
+ return value
3212
+ }
3213
+ switch tok {
3214
+ case token.ADD_ASSIGN:
3215
+ return left + " + " + right
3216
+ case token.SUB_ASSIGN:
3217
+ return left + " - " + right
3218
+ case token.MUL_ASSIGN:
3219
+ return left + " * " + right
3220
+ case token.QUO_ASSIGN:
3221
+ return left + " / " + right
3222
+ case token.REM_ASSIGN:
3223
+ return left + " % " + right
3224
+ case token.AND_ASSIGN:
3225
+ return left + " & " + right
3226
+ case token.OR_ASSIGN:
3227
+ return left + " | " + right
3228
+ case token.XOR_ASSIGN:
3229
+ return left + " ^ " + right
3230
+ case token.SHL_ASSIGN:
3231
+ return left + " << " + right
3232
+ case token.SHR_ASSIGN:
3233
+ return left + " >> " + right
3234
+ case token.AND_NOT_ASSIGN:
3235
+ return left + " & ~(" + right + ")"
3236
+ default:
3237
+ return right
3238
+ }
3239
+ }
3240
+
3241
+ func integerQuotientAssignExpr(targetType types.Type, left string, right string, tok token.Token) (string, bool) {
3242
+ value, ok := integerQuotientAssignValueExpr(targetType, left, right, tok)
3243
+ if !ok {
3244
+ return "", false
3245
+ }
3246
+ return left + " = " + value, true
3247
+ }
3248
+
3249
+ func assignmentTargetType(ctx lowerFileContext, lhs ast.Expr) types.Type {
3250
+ if ident, ok := lhs.(*ast.Ident); ok {
3251
+ if obj := ctx.semPkg.source.TypesInfo.Defs[ident]; obj != nil {
3252
+ return obj.Type()
3253
+ }
3254
+ }
3255
+ return ctx.semPkg.source.TypesInfo.TypeOf(lhs)
3256
+ }
3257
+
3258
+ func integerQuotientAssignValueExpr(targetType types.Type, left string, right string, tok token.Token) (string, bool) {
3259
+ if tok != token.QUO_ASSIGN || !isIntegerType(targetType) {
3260
+ return "", false
3261
+ }
3262
+ if bits, ok := unsignedIntegerBits(targetType); ok && bits <= 32 {
3263
+ return "(" + left + " / " + right + ") >>> 0", true
3264
+ }
3265
+ return "Math.trunc(" + left + " / " + right + ")", true
3266
+ }
3267
+
2747
3268
  func wideIntegerAssignHelper(targetType types.Type, tok token.Token) (RuntimeHelper, bool) {
2748
3269
  if !isFixedWideIntegerType(targetType) {
2749
3270
  return "", false
@@ -2754,17 +3275,21 @@ func wideIntegerAssignHelper(targetType types.Type, tok token.Token) (RuntimeHel
2754
3275
  case token.SHR_ASSIGN:
2755
3276
  return RuntimeHelperUint64Shr, true
2756
3277
  case token.MUL_ASSIGN:
2757
- return RuntimeHelperUint64Mul, true
3278
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Mul, RuntimeHelperInt64Mul), true
3279
+ case token.QUO_ASSIGN:
3280
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Div, RuntimeHelperInt64Div), true
3281
+ case token.REM_ASSIGN:
3282
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Mod, RuntimeHelperInt64Mod), true
2758
3283
  case token.ADD_ASSIGN:
2759
- return RuntimeHelperUint64Add, true
3284
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Add, RuntimeHelperInt64Add), true
2760
3285
  case token.SUB_ASSIGN:
2761
- return RuntimeHelperUint64Sub, true
3286
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Sub, RuntimeHelperInt64Sub), true
2762
3287
  case token.AND_ASSIGN:
2763
- return RuntimeHelperUint64And, true
3288
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64And, RuntimeHelperInt64And), true
2764
3289
  case token.OR_ASSIGN:
2765
- return RuntimeHelperUint64Or, true
3290
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Or, RuntimeHelperInt64Or), true
2766
3291
  case token.XOR_ASSIGN:
2767
- return RuntimeHelperUint64Xor, true
3292
+ return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Xor, RuntimeHelperInt64Xor), true
2768
3293
  default:
2769
3294
  return "", false
2770
3295
  }
@@ -2834,14 +3359,12 @@ func (o *LoweringOwner) shortDeclTypeAnnotation(ctx lowerFileContext, lhs ast.Ex
2834
3359
  if obj == nil {
2835
3360
  return ""
2836
3361
  }
2837
- if signature := unnamedSignatureForType(obj.Type()); signature != nil && rhsIsMethodValue(ctx, rhs) {
2838
- return ": " + o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
2839
- }
2840
3362
  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)
3363
+ typ := o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
3364
+ if ctx.model.needsVarRef[obj] {
3365
+ typ = "$.VarRef<" + typ + ">"
2844
3366
  }
3367
+ return ": " + typ
2845
3368
  }
2846
3369
  if !shortDeclNeedsTypeAnnotation(obj.Type()) {
2847
3370
  return ""
@@ -2852,9 +3375,11 @@ func (o *LoweringOwner) shortDeclTypeAnnotation(ctx lowerFileContext, lhs ast.Ex
2852
3375
  func shortDeclNeedsTypeAnnotation(typ types.Type) bool {
2853
3376
  switch typed := types.Unalias(typ).Underlying().(type) {
2854
3377
  case *types.Pointer:
2855
- return namedStructType(typed.Elem()) != nil
3378
+ return namedStructType(typed.Elem()) != nil || namedNonStructType(typed.Elem()) != nil
2856
3379
  case *types.Map:
2857
3380
  return true
3381
+ case *types.Slice:
3382
+ return true
2858
3383
  default:
2859
3384
  return false
2860
3385
  }
@@ -2895,7 +3420,7 @@ func (o *LoweringOwner) lowerStarTargetAssignmentStmt(
2895
3420
  lhs ast.Expr,
2896
3421
  right string,
2897
3422
  ) (loweredStmt, []Diagnostic, bool) {
2898
- star, ok := lhs.(*ast.StarExpr)
3423
+ star, ok := unwrapParenExpr(lhs).(*ast.StarExpr)
2899
3424
  if !ok {
2900
3425
  return loweredStmt{}, nil, false
2901
3426
  }
@@ -2915,7 +3440,7 @@ func (o *LoweringOwner) lowerTupleReassignmentStmt(
2915
3440
  diagnostics []Diagnostic,
2916
3441
  ) ([]loweredStmt, []Diagnostic) {
2917
3442
  tempName := ctx.tempName("Tuple")
2918
- stmts := []loweredStmt{{text: "let " + tempName + " = " + right}}
3443
+ stmts := []loweredStmt{{text: "let " + tempName + ": any = " + right}}
2919
3444
  for idx, lhs := range stmt.Lhs {
2920
3445
  if ident, ok := lhs.(*ast.Ident); ok && ident.Name == "_" {
2921
3446
  continue
@@ -3064,8 +3589,8 @@ func shortDeclDefShadowsOuterName(name string, def types.Object) bool {
3064
3589
  if scope == def.Parent() {
3065
3590
  continue
3066
3591
  }
3067
- obj, ok := scope.Lookup(name).(*types.Var)
3068
- if ok && obj.Pos().IsValid() && obj.Pos() < def.Pos() {
3592
+ obj := scope.Lookup(name)
3593
+ if obj != nil && obj.Pos().IsValid() && obj.Pos() < def.Pos() {
3069
3594
  return true
3070
3595
  }
3071
3596
  }
@@ -3281,6 +3806,9 @@ func (o *LoweringOwner) lowerReturnStmt(ctx lowerFileContext, stmt *ast.ReturnSt
3281
3806
  if ctx.rangeBranch != nil {
3282
3807
  return o.lowerRangeFuncReturnStmt(ctx, stmt)
3283
3808
  }
3809
+ if o.returnNeedsNamedResultDefer(ctx) {
3810
+ return o.lowerNamedResultDeferReturnStmt(ctx, stmt)
3811
+ }
3284
3812
  if len(stmt.Results) == 0 {
3285
3813
  if result, ok := o.lowerNamedResultReturn(ctx); ok {
3286
3814
  return "return " + result, nil
@@ -3313,6 +3841,125 @@ func (o *LoweringOwner) lowerReturnStmt(ctx lowerFileContext, stmt *ast.ReturnSt
3313
3841
  return "return [" + strings.Join(parts, ", ") + "]", diagnostics
3314
3842
  }
3315
3843
 
3844
+ func (o *LoweringOwner) returnNeedsNamedResultDefer(ctx lowerFileContext) bool {
3845
+ if ctx.deferState == nil || !ctx.deferState.used || ctx.signature == nil || ctx.signature.Results() == nil {
3846
+ return false
3847
+ }
3848
+ for result := range ctx.signature.Results().Variables() {
3849
+ if result.Name() != "" {
3850
+ return true
3851
+ }
3852
+ }
3853
+ return false
3854
+ }
3855
+
3856
+ func (o *LoweringOwner) lowerNamedResultDeferReturnStmt(ctx lowerFileContext, stmt *ast.ReturnStmt) (string, []Diagnostic) {
3857
+ var diagnostics []Diagnostic
3858
+ var lines []string
3859
+ explicitTemp := ""
3860
+ if len(stmt.Results) != 0 {
3861
+ var value string
3862
+ var values []string
3863
+ if len(stmt.Results) == 1 && ctx.signature.Results().Len() > 1 {
3864
+ expr, exprDiagnostics := o.lowerExpr(ctx, stmt.Results[0])
3865
+ diagnostics = append(diagnostics, exprDiagnostics...)
3866
+ if prefix, tuple, ok := o.lowerTupleReturnValue(ctx, stmt.Results[0], expr); ok {
3867
+ lines = append(lines, prefix)
3868
+ value = tuple
3869
+ } else {
3870
+ value = expr
3871
+ }
3872
+ } else {
3873
+ values = make([]string, 0, len(stmt.Results))
3874
+ for idx, result := range stmt.Results {
3875
+ expr, exprDiagnostics := o.lowerExpr(ctx, result)
3876
+ diagnostics = append(diagnostics, exprDiagnostics...)
3877
+ if idx < ctx.signature.Results().Len() {
3878
+ expr = o.lowerValueForTarget(ctx, result, ctx.signature.Results().At(idx).Type(), expr)
3879
+ }
3880
+ values = append(values, expr)
3881
+ }
3882
+ }
3883
+ temp := ctx.tempName("Return")
3884
+ explicitTemp = temp
3885
+ tempType := o.tsSignatureResultFor(ctx, ctx.signature)
3886
+ if value != "" {
3887
+ lines = append(lines, "const "+temp+": "+tempType+" = "+value)
3888
+ } else if len(values) == 1 {
3889
+ lines = append(lines, "const "+temp+": "+tempType+" = "+values[0])
3890
+ } else {
3891
+ lines = append(lines, "const "+temp+": "+tempType+" = ["+strings.Join(values, ", ")+"]")
3892
+ }
3893
+ for idx := range ctx.signature.Results().Len() {
3894
+ result := ctx.signature.Results().At(idx)
3895
+ name := result.Name()
3896
+ if name == "" || name == "_" {
3897
+ continue
3898
+ }
3899
+ target := safeIdentifier(name)
3900
+ if ctx.model.needsVarRef[result] {
3901
+ target += ".value"
3902
+ }
3903
+ source := temp
3904
+ if ctx.signature.Results().Len() > 1 {
3905
+ source += "[" + strconv.Itoa(idx) + "]"
3906
+ }
3907
+ lines = append(lines, target+" = "+source)
3908
+ }
3909
+ }
3910
+ lines = append(lines, o.lowerDeferDisposeStmt(ctx))
3911
+ if result, ok := o.lowerNamedResultReturnWithExplicitTemp(ctx, explicitTemp); ok {
3912
+ lines = append(lines, "return "+result)
3913
+ } else {
3914
+ lines = append(lines, "return")
3915
+ }
3916
+ return strings.Join(lines, "\n"), diagnostics
3917
+ }
3918
+
3919
+ func (o *LoweringOwner) lowerNamedResultReturnWithExplicitTemp(ctx lowerFileContext, explicitTemp string) (string, bool) {
3920
+ if explicitTemp == "" {
3921
+ return o.lowerNamedResultReturn(ctx)
3922
+ }
3923
+ parts := make([]string, 0, ctx.signature.Results().Len())
3924
+ hasNamedResult := false
3925
+ multi := ctx.signature.Results().Len() > 1
3926
+ for idx := range ctx.signature.Results().Len() {
3927
+ result := ctx.signature.Results().At(idx)
3928
+ name := result.Name()
3929
+ if name == "" || name == "_" {
3930
+ source := explicitTemp
3931
+ if multi {
3932
+ source += "[" + strconv.Itoa(idx) + "]"
3933
+ }
3934
+ parts = append(parts, source)
3935
+ if name != "" {
3936
+ hasNamedResult = true
3937
+ }
3938
+ continue
3939
+ }
3940
+ hasNamedResult = true
3941
+ returnExpr := safeIdentifier(name)
3942
+ if ctx.model.needsVarRef[result] {
3943
+ returnExpr += ".value"
3944
+ }
3945
+ parts = append(parts, returnExpr)
3946
+ }
3947
+ if !hasNamedResult {
3948
+ return "", false
3949
+ }
3950
+ if len(parts) == 1 {
3951
+ return parts[0], true
3952
+ }
3953
+ return "[" + strings.Join(parts, ", ") + "]", true
3954
+ }
3955
+
3956
+ func (o *LoweringOwner) lowerDeferDisposeStmt(ctx lowerFileContext) string {
3957
+ if ctx.deferState != nil && ctx.deferState.async {
3958
+ return "await __defer[Symbol.asyncDispose]()"
3959
+ }
3960
+ return "__defer[Symbol.dispose]()"
3961
+ }
3962
+
3316
3963
  func (o *LoweringOwner) lowerBodylessReturnStmt(ctx lowerFileContext, signature *types.Signature) (string, bool) {
3317
3964
  if signature.Results().Len() == 0 {
3318
3965
  return "", false
@@ -3434,6 +4081,9 @@ func genericCallResultUsesTypeParam(ctx lowerFileContext, expr ast.Expr) bool {
3434
4081
  return false
3435
4082
  }
3436
4083
  signature := genericFunctionSignatureForCall(ctx, call.Fun)
4084
+ if signature == nil {
4085
+ signature = sourceFunctionSignatureForCall(ctx, call.Fun)
4086
+ }
3437
4087
  if signature == nil || signature.Results() == nil || signature.Results().Len() != 1 {
3438
4088
  return false
3439
4089
  }
@@ -3446,6 +4096,9 @@ func genericCallTupleResultTypeParamIndexes(ctx lowerFileContext, expr ast.Expr)
3446
4096
  return nil
3447
4097
  }
3448
4098
  signature := genericFunctionSignatureForCall(ctx, call.Fun)
4099
+ if signature == nil {
4100
+ signature = sourceFunctionSignatureForCall(ctx, call.Fun)
4101
+ }
3449
4102
  if signature == nil || signature.Results() == nil || signature.Results().Len() < 2 {
3450
4103
  return nil
3451
4104
  }
@@ -3471,6 +4124,30 @@ func genericFunctionSignatureForCall(ctx lowerFileContext, fun ast.Expr) *types.
3471
4124
  }
3472
4125
  }
3473
4126
 
4127
+ func sourceFunctionSignatureForCall(ctx lowerFileContext, fun ast.Expr) *types.Signature {
4128
+ for {
4129
+ switch typed := ast.Unparen(fun).(type) {
4130
+ case *ast.IndexExpr:
4131
+ fun = typed.X
4132
+ case *ast.IndexListExpr:
4133
+ fun = typed.X
4134
+ default:
4135
+ if ctx.semPkg == nil || ctx.semPkg.source == nil {
4136
+ return nil
4137
+ }
4138
+ fn := calledFunction(ctx.semPkg.source, fun)
4139
+ if fn == nil {
4140
+ return nil
4141
+ }
4142
+ if origin := fn.Origin(); origin != nil {
4143
+ fn = origin
4144
+ }
4145
+ signature, _ := fn.Type().(*types.Signature)
4146
+ return signature
4147
+ }
4148
+ }
4149
+ }
4150
+
3474
4151
  func typeContainsTypeParam(typ types.Type) bool {
3475
4152
  return typeContainsTypeParamSeen(typ, make(map[types.Type]bool))
3476
4153
  }
@@ -3569,27 +4246,57 @@ func (o *LoweringOwner) lowerNamedResults(ctx lowerFileContext, signature *types
3569
4246
  }
3570
4247
 
3571
4248
  func (o *LoweringOwner) lowerNamedResultReturn(ctx lowerFileContext) (string, bool) {
3572
- results := o.lowerNamedResults(ctx, ctx.signature)
3573
- if len(results) == 0 {
4249
+ if ctx.signature == nil || ctx.signature.Results() == nil || ctx.signature.Results().Len() == 0 {
3574
4250
  return "", false
3575
4251
  }
3576
- if len(results) == 1 {
3577
- return results[0].returnExpr, true
4252
+ parts := make([]string, 0, ctx.signature.Results().Len())
4253
+ hasNamedResult := false
4254
+ for result := range ctx.signature.Results().Variables() {
4255
+ name := result.Name()
4256
+ if name == "" {
4257
+ parts = append(parts, o.lowerDeclarationZeroValueExpr(ctx, result.Type()))
4258
+ continue
4259
+ }
4260
+ hasNamedResult = true
4261
+ if name == "_" {
4262
+ parts = append(parts, o.lowerDeclarationZeroValueExpr(ctx, result.Type()))
4263
+ continue
4264
+ }
4265
+ returnExpr := safeIdentifier(name)
4266
+ if ctx.model.needsVarRef[result] {
4267
+ returnExpr += ".value"
4268
+ }
4269
+ parts = append(parts, returnExpr)
4270
+ }
4271
+ if !hasNamedResult {
4272
+ return "", false
3578
4273
  }
3579
- parts := make([]string, 0, len(results))
3580
- for _, result := range results {
3581
- parts = append(parts, result.returnExpr)
4274
+ if len(parts) == 1 {
4275
+ return parts[0], true
3582
4276
  }
3583
4277
  return "[" + strings.Join(parts, ", ") + "]", true
3584
4278
  }
3585
4279
 
3586
4280
  func (o *LoweringOwner) lowerForStmt(ctx lowerFileContext, stmt *ast.ForStmt) (loweredStmt, []Diagnostic) {
3587
- bodyCtx := ctx.withoutRangeLoopBranches()
4281
+ bodyCtx := ctx.withoutRangeLoopBranches().withoutLoopLabel()
3588
4282
  loopLabel := ""
3589
4283
  if stmtListNeedsLoopBranchLabel(stmt.Body.List) {
3590
4284
  loopLabel = ctx.tempName("Loop")
3591
4285
  bodyCtx = bodyCtx.withLoopLabel(loopLabel)
3592
4286
  }
4287
+ initCtx := ctx
4288
+ loopCtx := ctx
4289
+ var initPrelude []loweredStmt
4290
+ if assign, ok := stmt.Init.(*ast.AssignStmt); ok && assign.Tok == token.DEFINE {
4291
+ oldAliases, prelude := o.lowerShortDeclShadowAliases(ctx, assign)
4292
+ newAliases := o.lowerShortDeclNewShadowAliases(ctx, assign)
4293
+ if len(oldAliases) != 0 || len(newAliases) != 0 {
4294
+ initCtx = ctx.withIdentAliases(oldAliases).withIdentRefAliases(newAliases)
4295
+ loopCtx = ctx.withIdentRefAliases(newAliases)
4296
+ bodyCtx = bodyCtx.withIdentRefAliases(newAliases)
4297
+ initPrelude = prelude
4298
+ }
4299
+ }
3593
4300
  if stmt.Init == nil && stmt.Post == nil {
3594
4301
  cond := "true"
3595
4302
  var diagnostics []Diagnostic
@@ -3614,19 +4321,19 @@ func (o *LoweringOwner) lowerForStmt(ctx lowerFileContext, stmt *ast.ForStmt) (l
3614
4321
  init := ""
3615
4322
  var diagnostics []Diagnostic
3616
4323
  if stmt.Init != nil {
3617
- lowered, initDiagnostics := o.lowerForInitStmt(ctx, stmt.Init)
4324
+ lowered, initDiagnostics := o.lowerForInitStmt(initCtx, stmt.Init)
3618
4325
  diagnostics = append(diagnostics, initDiagnostics...)
3619
4326
  init = lowered
3620
4327
  }
3621
4328
  cond := ""
3622
4329
  if stmt.Cond != nil {
3623
4330
  var condDiagnostics []Diagnostic
3624
- cond, condDiagnostics = o.lowerExpr(ctx, stmt.Cond)
4331
+ cond, condDiagnostics = o.lowerExpr(loopCtx, stmt.Cond)
3625
4332
  diagnostics = append(diagnostics, condDiagnostics...)
3626
4333
  }
3627
4334
  post := ""
3628
4335
  if stmt.Post != nil {
3629
- lowered, postDiagnostics := o.lowerForPostStmt(ctx, stmt.Post)
4336
+ lowered, postDiagnostics := o.lowerForPostStmt(loopCtx, stmt.Post)
3630
4337
  diagnostics = append(diagnostics, postDiagnostics...)
3631
4338
  post = lowered
3632
4339
  }
@@ -3636,11 +4343,15 @@ func (o *LoweringOwner) lowerForStmt(ctx lowerFileContext, stmt *ast.ForStmt) (l
3636
4343
  if loopLabel != "" {
3637
4344
  text = loopLabel + ": " + text
3638
4345
  }
3639
- return loweredStmt{
4346
+ forStmt := loweredStmt{
3640
4347
  hasBlock: true,
3641
4348
  text: text,
3642
4349
  children: body,
3643
- }, diagnostics
4350
+ }
4351
+ if len(initPrelude) != 0 {
4352
+ return loweredStmt{children: append(initPrelude, forStmt)}, diagnostics
4353
+ }
4354
+ return forStmt, diagnostics
3644
4355
  }
3645
4356
 
3646
4357
  func (o *LoweringOwner) lowerForInitStmt(ctx lowerFileContext, stmt ast.Stmt) (string, []Diagnostic) {
@@ -3729,9 +4440,13 @@ func (o *LoweringOwner) lowerForPostStmt(ctx lowerFileContext, stmt ast.Stmt) (s
3729
4440
  diagnostics = append(diagnostics, leftDiagnostics...)
3730
4441
  lefts = append(lefts, left)
3731
4442
  }
3732
- for _, rhs := range assign.Rhs {
4443
+ for idx, rhs := range assign.Rhs {
3733
4444
  right, rightDiagnostics := o.lowerExpr(ctx, rhs)
3734
4445
  diagnostics = append(diagnostics, rightDiagnostics...)
4446
+ if idx < len(assign.Lhs) {
4447
+ targetType := ctx.semPkg.source.TypesInfo.TypeOf(assign.Lhs[idx])
4448
+ right = o.lowerValueForTarget(ctx, rhs, targetType, right)
4449
+ }
3735
4450
  rights = append(rights, right)
3736
4451
  }
3737
4452
  return "[" + strings.Join(lefts, ", ") + "] = [" + strings.Join(rights, ", ") + "]", diagnostics
@@ -3746,7 +4461,7 @@ func (o *LoweringOwner) lowerForPostStmt(ctx lowerFileContext, stmt ast.Stmt) (s
3746
4461
  func (o *LoweringOwner) lowerRangeStmt(ctx lowerFileContext, stmt *ast.RangeStmt) (loweredStmt, []Diagnostic) {
3747
4462
  rangeValue, diagnostics := o.lowerExpr(ctx, stmt.X)
3748
4463
  aliases := o.lowerRangeDeclShadowAliases(ctx, stmt)
3749
- bodyCtx := ctx
4464
+ bodyCtx := ctx.withoutLoopLabel()
3750
4465
  if len(aliases) != 0 {
3751
4466
  bodyCtx = bodyCtx.withIdentAliases(aliases)
3752
4467
  }
@@ -3795,23 +4510,21 @@ func (o *LoweringOwner) lowerRangeStmt(ctx lowerFileContext, stmt *ast.RangeStmt
3795
4510
  if strings.HasPrefix(rangeTarget, "await ") {
3796
4511
  rangeTarget = "(" + rangeTarget + ")"
3797
4512
  }
3798
- key := keyName
3799
- if key == "" {
3800
- key = "__rangeKey"
3801
- }
3802
- value := valueName
3803
- if value == "" {
3804
- value = "__rangeValue"
3805
- }
4513
+ key, keyBindings, keyDiagnostics := o.lowerMapRangeBinding(ctx, stmt.Key, keyName, "__rangeKey", "RangeKey", stmt.Tok == token.DEFINE)
4514
+ value, valueBindings, valueDiagnostics := o.lowerMapRangeBinding(ctx, stmt.Value, valueName, "__rangeValue", "RangeValue", stmt.Tok == token.DEFINE)
4515
+ diagnostics = append(diagnostics, keyDiagnostics...)
4516
+ diagnostics = append(diagnostics, valueDiagnostics...)
3806
4517
  binding := "const"
3807
4518
  if rangeBindingAssignedInBody(ctx, stmt.Key, stmt.Body) ||
3808
4519
  rangeBindingAssignedInBody(ctx, stmt.Value, stmt.Body) {
3809
4520
  binding = "let"
3810
4521
  }
4522
+ children := append(keyBindings, valueBindings...)
4523
+ children = append(children, body...)
3811
4524
  return loweredStmt{
3812
4525
  hasBlock: true,
3813
4526
  text: "for (" + binding + " [" + key + ", " + value + "] of " + rangeTarget + "?.entries() ?? [])",
3814
- children: body,
4527
+ children: children,
3815
4528
  }, diagnostics
3816
4529
  }
3817
4530
  if isStringType(rangeType) {
@@ -3848,8 +4561,12 @@ func (o *LoweringOwner) lowerRangeStmt(ctx lowerFileContext, stmt *ast.RangeStmt
3848
4561
 
3849
4562
  body, bodyDiagnostics := o.lowerBlock(bodyCtx.withoutRangeLoopBranches(), stmt.Body)
3850
4563
  diagnostics = append(diagnostics, bodyDiagnostics...)
3851
- rangeTarget := o.lowerArrayPointerTarget(ctx, rangeValue, rangeType)
3852
- indexTarget := o.lowerIndexTarget(ctx, rangeValue, rangeType)
4564
+ rangeTarget := ctx.tempName("RangeTarget")
4565
+ rangeTargetValue := o.lowerArrayPointerTarget(ctx, rangeValue, rangeType)
4566
+ indexTarget := rangeTarget
4567
+ if isNilableType(rangeType) {
4568
+ indexTarget += "!"
4569
+ }
3853
4570
  indexName := keyName
3854
4571
  if indexName == "" {
3855
4572
  indexName = "__rangeIndex"
@@ -3864,7 +4581,7 @@ func (o *LoweringOwner) lowerRangeStmt(ctx lowerFileContext, stmt *ast.RangeStmt
3864
4581
  }
3865
4582
  return loweredStmt{
3866
4583
  hasBlock: true,
3867
- text: "for (let " + indexName + " = 0; " + indexName + " < " + o.runtimeOwner.QualifiedHelper(RuntimeHelperLen) + "(" + rangeTarget + "); " + indexName + "++)",
4584
+ text: "for (let " + rangeTarget + " = " + rangeTargetValue + ", " + indexName + " = 0; " + indexName + " < " + o.runtimeOwner.QualifiedHelper(RuntimeHelperLen) + "(" + rangeTarget + "); " + indexName + "++)",
3868
4585
  children: children,
3869
4586
  }, diagnostics
3870
4587
  }
@@ -3933,18 +4650,19 @@ func (o *LoweringOwner) lowerRangeFuncStmt(
3933
4650
  rangeBranch.value = ctx.tempName("RangeReturnValue")
3934
4651
  rangeBranch.resultType = o.tsSignatureResultFor(ctx, ctx.signature)
3935
4652
  }
3936
- body, diagnostics := o.lowerBlock(ctx.withRangeBranch(rangeBranch), stmt.Body)
4653
+ body, diagnostics := o.lowerBlock(ctx.withoutLoopLabel().withRangeBranch(rangeBranch), stmt.Body)
3937
4654
  if stmt.Tok != token.DEFINE {
3938
4655
  assignments, assignmentDiagnostics := o.lowerRangeFuncAssignments(ctx, stmt, paramNames)
3939
4656
  diagnostics = append(diagnostics, assignmentDiagnostics...)
3940
4657
  body = append(assignments, body...)
3941
4658
  }
4659
+ async := ctx.asyncFunction
3942
4660
 
3943
4661
  return loweredStmt{rangeFunc: &loweredRangeFunc{
3944
4662
  value: rangeValue,
3945
4663
  params: paramNames,
3946
4664
  body: body,
3947
- async: stmtsContainAwait(body) || o.rangeFunctionValueNeedsAwait(ctx, stmt.X),
4665
+ async: async,
3948
4666
  returnBranch: rangeBranch,
3949
4667
  parentBranch: parentBranch,
3950
4668
  }}, diagnostics
@@ -3989,6 +4707,7 @@ func (o *LoweringOwner) lowerSelectStmt(ctx lowerFileContext, stmt *ast.SelectSt
3989
4707
  lowered := &loweredSelect{
3990
4708
  hasReturn: selectName + "HasReturn",
3991
4709
  value: selectName + "Value",
4710
+ result: selectName + "Result",
3992
4711
  resultType: resultType,
3993
4712
  }
3994
4713
  var diagnostics []Diagnostic
@@ -4025,7 +4744,7 @@ func (o *LoweringOwner) lowerSelectStmt(ctx lowerFileContext, stmt *ast.SelectSt
4025
4744
  })
4026
4745
  caseID++
4027
4746
  case *ast.ExprStmt:
4028
- channel, prelude, receiveDiagnostics := o.lowerSelectReceiveComm(ctx, nil, comm.X)
4747
+ channel, prelude, receiveDiagnostics := o.lowerSelectReceiveComm(ctx, nil, comm.X, lowered.result)
4029
4748
  body, bodyDiagnostics := o.lowerStmtList(ctx.withLocalScope().withoutRangeBreak(), clause.Body)
4030
4749
  diagnostics = append(diagnostics, receiveDiagnostics...)
4031
4750
  diagnostics = append(diagnostics, bodyDiagnostics...)
@@ -4037,7 +4756,7 @@ func (o *LoweringOwner) lowerSelectStmt(ctx lowerFileContext, stmt *ast.SelectSt
4037
4756
  })
4038
4757
  caseID++
4039
4758
  case *ast.AssignStmt:
4040
- channel, prelude, receiveDiagnostics := o.lowerSelectReceiveComm(ctx, comm, nil)
4759
+ channel, prelude, receiveDiagnostics := o.lowerSelectReceiveComm(ctx, comm, nil, lowered.result)
4041
4760
  body, bodyDiagnostics := o.lowerStmtList(ctx.withLocalScope().withoutRangeBreak(), clause.Body)
4042
4761
  diagnostics = append(diagnostics, receiveDiagnostics...)
4043
4762
  diagnostics = append(diagnostics, bodyDiagnostics...)
@@ -4083,11 +4802,22 @@ func stmtsEndInReturn(stmts []loweredStmt) bool {
4083
4802
  return false
4084
4803
  }
4085
4804
  last := stmts[len(stmts)-1]
4086
- if strings.HasPrefix(strings.TrimSpace(last.text), "return") {
4805
+ return stmtEndsInReturn(last)
4806
+ }
4807
+
4808
+ func stmtEndsInReturn(stmt loweredStmt) bool {
4809
+ trimmed := strings.TrimSpace(stmt.text)
4810
+ if strings.HasPrefix(trimmed, "return") {
4087
4811
  return true
4088
4812
  }
4089
- if last.selectStmt != nil {
4090
- return last.selectStmt.returns
4813
+ if stmt.selectStmt != nil {
4814
+ return stmt.selectStmt.returns
4815
+ }
4816
+ if trimmed == "" && (stmt.hasBlock || len(stmt.children) != 0) {
4817
+ return stmtsEndInReturn(stmt.children)
4818
+ }
4819
+ if strings.HasPrefix(trimmed, "if ") && len(stmt.elseBody) != 0 {
4820
+ return stmtsEndInReturn(stmt.children) && stmtsEndInReturn(stmt.elseBody)
4091
4821
  }
4092
4822
  return false
4093
4823
  }
@@ -4134,6 +4864,7 @@ func (o *LoweringOwner) lowerSelectReceiveComm(
4134
4864
  ctx lowerFileContext,
4135
4865
  assign *ast.AssignStmt,
4136
4866
  expr ast.Expr,
4867
+ resultName string,
4137
4868
  ) (string, []loweredStmt, []Diagnostic) {
4138
4869
  receiveExpr := expr
4139
4870
  if assign != nil && len(assign.Rhs) == 1 {
@@ -4162,7 +4893,7 @@ func (o *LoweringOwner) lowerSelectReceiveComm(
4162
4893
  if assign.Tok == token.DEFINE && isShortAssignTargetNew(ctx, lhs) {
4163
4894
  prefix = "let "
4164
4895
  }
4165
- prelude = append(prelude, loweredStmt{text: prefix + left + " = result" + fields[idx]})
4896
+ prelude = append(prelude, loweredStmt{text: prefix + left + " = " + resultName + fields[idx]})
4166
4897
  }
4167
4898
  return channel, prelude, diagnostics
4168
4899
  }
@@ -4177,15 +4908,24 @@ func (o *LoweringOwner) lowerSwitchStmt(ctx lowerFileContext, stmt *ast.SwitchSt
4177
4908
  }
4178
4909
 
4179
4910
  value := "true"
4911
+ var tagType types.Type
4180
4912
  if stmt.Tag != nil {
4181
4913
  var valueDiagnostics []Diagnostic
4182
4914
  value, valueDiagnostics = o.lowerExpr(ctx, stmt.Tag)
4183
4915
  diagnostics = append(diagnostics, valueDiagnostics...)
4184
4916
  value = lowerConstantComparableValue(ctx, stmt.Tag, value)
4917
+ tagType = ctx.semPkg.source.TypesInfo.TypeOf(stmt.Tag)
4185
4918
  } else if switchHasConstantCaseExpr(ctx, stmt) {
4186
4919
  value = "(true as boolean)"
4187
4920
  }
4188
4921
 
4922
+ compareCases := tagType != nil && isInterfaceType(tagType)
4923
+ compareValue := value
4924
+ if compareCases {
4925
+ compareValue = ctx.tempName("Switch")
4926
+ init = append(init, loweredStmt{text: "let " + compareValue + " = " + value})
4927
+ value = "true"
4928
+ }
4189
4929
  switchIR := &loweredSwitch{value: value}
4190
4930
  for _, raw := range stmt.Body.List {
4191
4931
  clause, ok := raw.(*ast.CaseClause)
@@ -4207,6 +4947,11 @@ func (o *LoweringOwner) lowerSwitchStmt(ctx lowerFileContext, stmt *ast.SwitchSt
4207
4947
  for _, expr := range clause.List {
4208
4948
  lowered, exprDiagnostics := o.lowerExpr(ctx, expr)
4209
4949
  diagnostics = append(diagnostics, exprDiagnostics...)
4950
+ if compareCases {
4951
+ sourceType := ctx.semPkg.source.TypesInfo.TypeOf(expr)
4952
+ lowered = o.lowerValueForTargetTypes(ctx, tagType, sourceType, lowered, shouldCloneStructValue(expr))
4953
+ lowered = o.runtimeOwner.QualifiedHelper(RuntimeHelperComparableEqual) + "(" + compareValue + ", " + lowered + ")"
4954
+ }
4210
4955
  values = append(values, lowered)
4211
4956
  }
4212
4957
  switchIR.cases = append(switchIR.cases, loweredSwitchCase{
@@ -4309,7 +5054,7 @@ func (o *LoweringOwner) lowerTypeSwitchStmt(ctx lowerFileContext, stmt *ast.Type
4309
5054
  if typ == nil {
4310
5055
  tsTypes = append(tsTypes, "any")
4311
5056
  } else {
4312
- tsTypes = append(tsTypes, o.tsTypeFor(ctx, typ))
5057
+ tsTypes = append(tsTypes, o.tsTypeSwitchCaseTypeFor(ctx, typ))
4313
5058
  }
4314
5059
  }
4315
5060
  switchIR.cases = append(switchIR.cases, loweredTypeSwitchCase{
@@ -4323,6 +5068,15 @@ func (o *LoweringOwner) lowerTypeSwitchStmt(ctx lowerFileContext, stmt *ast.Type
4323
5068
  return lowered, diagnostics
4324
5069
  }
4325
5070
 
5071
+ func (o *LoweringOwner) tsTypeSwitchCaseTypeFor(ctx lowerFileContext, typ types.Type) string {
5072
+ if named, ok := types.Unalias(typ).(*types.Named); ok {
5073
+ if _, ok := named.Underlying().(*types.Interface); ok {
5074
+ return o.tsNonNilTypeFor(ctx, named)
5075
+ }
5076
+ }
5077
+ return o.tsTypeFor(ctx, typ)
5078
+ }
5079
+
4326
5080
  func loweredStmtsUseVarRefName(stmts []loweredStmt, name string) bool {
4327
5081
  if name == "" {
4328
5082
  return false
@@ -4518,52 +5272,176 @@ func (o *LoweringOwner) lowerArrayEqualityExpr(ctx lowerFileContext, expr *ast.B
4518
5272
  return value, true
4519
5273
  }
4520
5274
 
4521
- func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
4522
- switch typed := expr.(type) {
4523
- case *ast.BasicLit:
4524
- return lowerBasicLit(typed), nil
4525
- case *ast.Ident:
4526
- return o.lowerIdent(ctx, typed, false), nil
4527
- case *ast.BinaryExpr:
4528
- if value := ctx.semPkg.source.TypesInfo.Types[typed].Value; value != nil {
4529
- if constantValue, ok := lowerLargeIntegerConstantValue(value); ok {
4530
- return constantValue, nil
4531
- }
4532
- }
4533
- if isEqualityOperator(typed.Op) {
4534
- if value, diagnostics, ok := o.lowerAddressEqualityExpr(ctx, typed); ok {
4535
- return value, diagnostics
4536
- }
4537
- }
4538
- left, leftDiagnostics := o.lowerExpr(ctx, typed.X)
4539
- right, rightDiagnostics := o.lowerExpr(ctx, typed.Y)
4540
- if _, ok := typed.X.(*ast.BinaryExpr); ok {
4541
- left = "(" + left + ")"
4542
- }
4543
- if _, ok := typed.Y.(*ast.BinaryExpr); ok {
4544
- right = "(" + right + ")"
4545
- }
4546
- if typed.Op == token.AND_NOT {
4547
- return left + " & ~(" + right + ")", append(leftDiagnostics, rightDiagnostics...)
4548
- }
4549
- if isEqualityOperator(typed.Op) {
4550
- if value, ok := o.lowerArrayEqualityExpr(ctx, typed, left, right); ok {
4551
- return value, append(leftDiagnostics, rightDiagnostics...)
4552
- }
4553
- left, right = o.lowerEqualityOperands(ctx, typed, left, right)
4554
- }
4555
- if typed.Op == token.QUO && isIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(typed)) {
4556
- return "Math.trunc(" + left + " / " + right + ")", append(leftDiagnostics, rightDiagnostics...)
4557
- }
4558
- if typed.Op == token.SHR {
4559
- if bits, ok := unsignedIntegerBits(ctx.semPkg.source.TypesInfo.TypeOf(typed.X)); ok && bits <= 32 {
4560
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUintShr) +
4561
- "(" + left + ", " + right + ", " + strconv.Itoa(bits) + ")", append(leftDiagnostics, rightDiagnostics...)
5275
+ func (o *LoweringOwner) lowerComplexEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
5276
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5277
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
5278
+ if !isComplexType(leftType) || !isComplexType(rightType) {
5279
+ return "", false
5280
+ }
5281
+ value := o.runtimeOwner.QualifiedHelper(RuntimeHelperArrayEqual) + "(" + left + ", " + right + ")"
5282
+ if expr.Op == token.NEQ {
5283
+ value = "!" + value
5284
+ }
5285
+ return value, true
5286
+ }
5287
+
5288
+ func (o *LoweringOwner) lowerStringEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
5289
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5290
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
5291
+ if !isStringType(leftType) || !isStringType(rightType) {
5292
+ return "", false
5293
+ }
5294
+ value := o.runtimeOwner.QualifiedHelper(RuntimeHelperStringEqual) + "(" + left + ", " + right + ")"
5295
+ if expr.Op == token.NEQ {
5296
+ value = "!" + value
5297
+ }
5298
+ return value, true
5299
+ }
5300
+
5301
+ func (o *LoweringOwner) lowerInterfaceEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
5302
+ if isNilExpr(expr.X) || isNilExpr(expr.Y) {
5303
+ return "", false
5304
+ }
5305
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5306
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
5307
+ if !isInterfaceType(leftType) && !isInterfaceType(rightType) {
5308
+ return "", false
5309
+ }
5310
+ value := o.runtimeOwner.QualifiedHelper(RuntimeHelperComparableEqual) + "(" + left + ", " + right + ")"
5311
+ if expr.Op == token.NEQ {
5312
+ value = "!" + value
5313
+ }
5314
+ return value, true
5315
+ }
5316
+
5317
+ func (o *LoweringOwner) lowerStringOrderExpr(
5318
+ ctx lowerFileContext,
5319
+ expr *ast.BinaryExpr,
5320
+ left string,
5321
+ right string,
5322
+ leftDiagnostics []Diagnostic,
5323
+ rightDiagnostics []Diagnostic,
5324
+ ) (string, []Diagnostic, bool) {
5325
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5326
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
5327
+ if !isStringType(leftType) || !isStringType(rightType) {
5328
+ return "", nil, false
5329
+ }
5330
+ left, leftDiagnostics = o.lowerStringOrderOperand(ctx, expr.X, left, leftDiagnostics)
5331
+ right, rightDiagnostics = o.lowerStringOrderOperand(ctx, expr.Y, right, rightDiagnostics)
5332
+ compare := o.runtimeOwner.QualifiedHelper(RuntimeHelperStringCompare) + "(" + left + ", " + right + ")"
5333
+ switch expr.Op {
5334
+ case token.LSS:
5335
+ return compare + " < 0", append(leftDiagnostics, rightDiagnostics...), true
5336
+ case token.LEQ:
5337
+ return compare + " <= 0", append(leftDiagnostics, rightDiagnostics...), true
5338
+ case token.GTR:
5339
+ return compare + " > 0", append(leftDiagnostics, rightDiagnostics...), true
5340
+ case token.GEQ:
5341
+ return compare + " >= 0", append(leftDiagnostics, rightDiagnostics...), true
5342
+ default:
5343
+ return "", nil, false
5344
+ }
5345
+ }
5346
+
5347
+ func (o *LoweringOwner) lowerStringOrderOperand(
5348
+ ctx lowerFileContext,
5349
+ expr ast.Expr,
5350
+ fallback string,
5351
+ fallbackDiagnostics []Diagnostic,
5352
+ ) (string, []Diagnostic) {
5353
+ call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
5354
+ if !ok || len(call.Args) != 1 {
5355
+ return fallback, fallbackDiagnostics
5356
+ }
5357
+ targetType := typeFromExpr(ctx, call.Fun)
5358
+ sourceType := ctx.semPkg.source.TypesInfo.TypeOf(call.Args[0])
5359
+ if targetType == nil || sourceType == nil || !isStringType(targetType) || !isByteSliceType(sourceType) {
5360
+ return fallback, fallbackDiagnostics
5361
+ }
5362
+ return o.lowerExpr(ctx, call.Args[0])
5363
+ }
5364
+
5365
+ func binaryOperandUsesTypeParam(ctx lowerFileContext, expr ast.Expr) bool {
5366
+ typ := ctx.semPkg.source.TypesInfo.TypeOf(expr)
5367
+ _, ok := types.Unalias(typ).(*types.TypeParam)
5368
+ return ok
5369
+ }
5370
+
5371
+ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
5372
+ if value := ctx.semPkg.source.TypesInfo.Types[unwrapParenExpr(expr)].Value; value != nil && value.Kind() == constant.Complex {
5373
+ if constantValue, ok := lowerConstantValue(value); ok {
5374
+ return constantValue, nil
5375
+ }
5376
+ }
5377
+ switch typed := expr.(type) {
5378
+ case *ast.BasicLit:
5379
+ return lowerBasicLit(typed), nil
5380
+ case *ast.Ident:
5381
+ return o.lowerIdent(ctx, typed, false), nil
5382
+ case *ast.BinaryExpr:
5383
+ if value := ctx.semPkg.source.TypesInfo.Types[typed].Value; value != nil {
5384
+ if (typed.Op == token.SHL || typed.Op == token.SHR) && (value.Kind() == constant.Int || value.Kind() == constant.Float) {
5385
+ if constantValue, ok := lowerConstantValue(value); ok {
5386
+ return constantValue, nil
5387
+ }
5388
+ }
5389
+ if constantValue, ok := lowerLargeIntegerConstantValue(value); ok {
5390
+ return constantValue, nil
5391
+ }
5392
+ }
5393
+ if isEqualityOperator(typed.Op) {
5394
+ if value, diagnostics, ok := o.lowerAddressEqualityExpr(ctx, typed); ok {
5395
+ return value, diagnostics
5396
+ }
5397
+ }
5398
+ left, leftDiagnostics := o.lowerExpr(ctx, typed.X)
5399
+ right, rightDiagnostics := o.lowerExpr(ctx, typed.Y)
5400
+ if _, ok := typed.X.(*ast.BinaryExpr); ok {
5401
+ left = "(" + left + ")"
5402
+ }
5403
+ if _, ok := typed.Y.(*ast.BinaryExpr); ok {
5404
+ right = "(" + right + ")"
5405
+ }
5406
+ if typed.Op == token.AND_NOT {
5407
+ return left + " & ~(" + right + ")", append(leftDiagnostics, rightDiagnostics...)
5408
+ }
5409
+ if isEqualityOperator(typed.Op) {
5410
+ if value, ok := o.lowerArrayEqualityExpr(ctx, typed, left, right); ok {
5411
+ return value, append(leftDiagnostics, rightDiagnostics...)
5412
+ }
5413
+ if value, ok := o.lowerComplexEqualityExpr(ctx, typed, left, right); ok {
5414
+ return value, append(leftDiagnostics, rightDiagnostics...)
5415
+ }
5416
+ if value, ok := o.lowerStringEqualityExpr(ctx, typed, left, right); ok {
5417
+ return value, append(leftDiagnostics, rightDiagnostics...)
5418
+ }
5419
+ if value, ok := o.lowerInterfaceEqualityExpr(ctx, typed, left, right); ok {
5420
+ return value, append(leftDiagnostics, rightDiagnostics...)
4562
5421
  }
5422
+ left, right = o.lowerEqualityOperands(ctx, typed, left, right)
4563
5423
  }
4564
5424
  if value, ok := o.lowerWideIntegerBinaryExpr(ctx, typed, left, right); ok {
4565
5425
  return value, append(leftDiagnostics, rightDiagnostics...)
4566
5426
  }
5427
+ if typed.Op == token.QUO && isIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(typed)) {
5428
+ return "Math.trunc(" + left + " / " + right + ")", append(leftDiagnostics, rightDiagnostics...)
5429
+ }
5430
+ if typed.Op == token.SHR {
5431
+ if bits, ok := unsignedIntegerBits(ctx.semPkg.source.TypesInfo.TypeOf(typed.X)); ok && bits <= 32 {
5432
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUintShr) +
5433
+ "(" + left + ", " + right + ", " + strconv.Itoa(bits) + ")", append(leftDiagnostics, rightDiagnostics...)
5434
+ }
5435
+ }
5436
+ if value, diagnostics, ok := o.lowerStringOrderExpr(ctx, typed, left, right, leftDiagnostics, rightDiagnostics); ok {
5437
+ return value, diagnostics
5438
+ }
5439
+ if binaryOperandUsesTypeParam(ctx, typed.X) {
5440
+ left = "(" + left + " as any)"
5441
+ }
5442
+ if binaryOperandUsesTypeParam(ctx, typed.Y) {
5443
+ right = "(" + right + " as any)"
5444
+ }
4567
5445
  return left + " " + typed.Op.String() + " " + right, append(leftDiagnostics, rightDiagnostics...)
4568
5446
  case *ast.UnaryExpr:
4569
5447
  if typed.Op == token.AND {
@@ -4575,7 +5453,7 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
4575
5453
  }
4576
5454
  value, diagnostics := o.lowerExpr(ctx, typed.X)
4577
5455
  if typed.Op == token.NOT || typed.Op == token.SUB || typed.Op == token.ADD {
4578
- return typed.Op.String() + value, diagnostics
5456
+ return lowerPrefixUnaryExpr(typed.Op, value), diagnostics
4579
5457
  }
4580
5458
  if typed.Op == token.XOR {
4581
5459
  return "~" + value, diagnostics
@@ -4621,7 +5499,7 @@ func lowerBasicLit(lit *ast.BasicLit) string {
4621
5499
  if err != nil {
4622
5500
  return strconv.Quote(lit.Value)
4623
5501
  }
4624
- return strconv.Quote(value)
5502
+ return lowerGoStringLiteral(value)
4625
5503
  }
4626
5504
  if lit.Kind == token.INT && isLegacyOctalLiteral(lit.Value) {
4627
5505
  digits := strings.TrimLeft(strings.ReplaceAll(lit.Value, "_", ""), "0")
@@ -4665,8 +5543,17 @@ func (o *LoweringOwner) lowerFuncLit(ctx lowerFileContext, lit *ast.FuncLit) (st
4665
5543
  if asyncCompatibleParams || funcLiteralUsesFunctionIdentifierCall(ctx, lit) {
4666
5544
  bodyCtx = bodyCtx.withAsyncFunction(true)
4667
5545
  }
5546
+ var params []loweredParam
5547
+ var paramBindings []loweredStmt
5548
+ if signature != nil && signature.Params() != nil {
5549
+ for idx := range signature.Params().Len() {
5550
+ param := signature.Params().At(idx)
5551
+ params, paramBindings = o.appendLoweredParam(ctx, params, paramBindings, param, idx, asyncCompatibleParams)
5552
+ }
5553
+ }
4668
5554
  body, diagnostics := o.lowerBlock(bodyCtx, lit.Body)
4669
5555
  var rendered strings.Builder
5556
+ renderStmts(&rendered, paramBindings, 1)
4670
5557
  renderNamedResults(&rendered, o.lowerNamedResults(ctx, signature), 1)
4671
5558
  renderDeferStack(&rendered, deferState, 1)
4672
5559
  renderStmts(&rendered, body, 1)
@@ -4675,21 +5562,28 @@ func (o *LoweringOwner) lowerFuncLit(ctx lowerFileContext, lit *ast.FuncLit) (st
4675
5562
  if async {
4676
5563
  prefix = "async "
4677
5564
  }
4678
- function := prefix + "(" + o.tsSignatureParamsFor(ctx, signature, asyncCompatibleParams) + "): " +
5565
+ function := prefix + "(" + renderLoweredParams(params) + "): " +
4679
5566
  asyncResultType(o.tsSignatureResultFor(ctx, signature), async) + " => {\n" +
4680
5567
  rendered.String() + "}"
4681
5568
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperFunctionValue) +
4682
5569
  "(" + function + ", " + o.runtimeFunctionTypeInfo(signature, "") + ")", async, diagnostics
4683
5570
  }
4684
5571
 
5572
+ func renderLoweredParams(params []loweredParam) string {
5573
+ if len(params) == 0 {
5574
+ return ""
5575
+ }
5576
+ rendered := make([]string, 0, len(params))
5577
+ for _, param := range params {
5578
+ rendered = append(rendered, param.name+": "+param.typ)
5579
+ }
5580
+ return strings.Join(rendered, ", ")
5581
+ }
5582
+
4685
5583
  func funcLiteralUsesFunctionIdentifierCall(ctx lowerFileContext, lit *ast.FuncLit) bool {
4686
5584
  if lit == nil || lit.Body == nil || ctx.semPkg == nil || ctx.semPkg.source == nil {
4687
5585
  return false
4688
5586
  }
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
5587
  uses := false
4694
5588
  ast.Inspect(lit.Body, func(node ast.Node) bool {
4695
5589
  if uses {
@@ -4760,6 +5654,9 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
4760
5654
  }
4761
5655
  obj := objectForIdent(ctx, ident)
4762
5656
  if alias := ctx.identAliases[obj]; alias != "" {
5657
+ if !raw && obj != nil && ctx.identAliasRefs[obj] && ctx.model.needsVarRef[obj] {
5658
+ return alias + ".value"
5659
+ }
4763
5660
  return alias
4764
5661
  }
4765
5662
  if constObj, ok := obj.(*types.Const); ok && ctx.localAliases[obj] != "" {
@@ -4770,22 +5667,22 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
4770
5667
  if alias := ctx.localAliases[obj]; alias != "" {
4771
5668
  if ctx.lazyPackageVars[obj] {
4772
5669
  lazyValue := alias + "." + packageVarGetterName(value) + "()"
4773
- if obj != nil && ctx.model.needsVarRef[obj] {
4774
- return lazyValue + ".value"
5670
+ if raw {
5671
+ return lazyValue
4775
5672
  }
4776
- return lazyValue
5673
+ return o.lowerPackageVarReadValue(ctx, obj, lazyValue)
5674
+ }
5675
+ if raw {
5676
+ return alias + "." + value
4777
5677
  }
4778
- return alias + "." + value
5678
+ return o.lowerPackageVarReadValue(ctx, obj, alias+"."+value)
4779
5679
  }
4780
5680
  if raw {
4781
5681
  return value
4782
5682
  }
4783
5683
  if ctx.lazyPackageVars[obj] {
4784
5684
  lazyValue := packageVarGetterName(value) + "()"
4785
- if obj != nil && ctx.model.needsVarRef[obj] {
4786
- return lazyValue + ".value"
4787
- }
4788
- return lazyValue
5685
+ return o.lowerPackageVarReadValue(ctx, obj, lazyValue)
4789
5686
  }
4790
5687
  if obj != nil && ctx.model.needsVarRef[obj] {
4791
5688
  return value + ".value"
@@ -4793,6 +5690,17 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
4793
5690
  return value
4794
5691
  }
4795
5692
 
5693
+ func (o *LoweringOwner) lowerPackageVarReadValue(ctx lowerFileContext, obj types.Object, value string) string {
5694
+ if obj == nil || ctx.model == nil || !ctx.model.needsVarRef[obj] {
5695
+ return value
5696
+ }
5697
+ if varObj, ok := obj.(*types.Var); ok && packageVarReadNeedsPointerValue(varObj.Type()) {
5698
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
5699
+ "<" + o.tsNonNilTypeFor(ctx, varObj.Type()) + ">(" + value + ")"
5700
+ }
5701
+ return value + ".value"
5702
+ }
5703
+
4796
5704
  func objectForIdent(ctx lowerFileContext, ident *ast.Ident) types.Object {
4797
5705
  if ctx.semPkg == nil || ctx.semPkg.source == nil {
4798
5706
  return nil
@@ -4820,6 +5728,28 @@ func objectForValueExpr(ctx lowerFileContext, expr ast.Expr) types.Object {
4820
5728
  }
4821
5729
  }
4822
5730
 
5731
+ func objectNeedsVarRef(ctx lowerFileContext, obj types.Object) bool {
5732
+ if obj == nil || ctx.model == nil {
5733
+ return false
5734
+ }
5735
+ if ctx.model.needsVarRef[obj] {
5736
+ return true
5737
+ }
5738
+ if obj.Pkg() == nil {
5739
+ return false
5740
+ }
5741
+ semPkg := ctx.model.packages[obj.Pkg().Path()]
5742
+ if semPkg == nil {
5743
+ return false
5744
+ }
5745
+ for _, value := range semPkg.values {
5746
+ if value.name == obj.Name() && ctx.model.needsVarRef[value.object] {
5747
+ return true
5748
+ }
5749
+ }
5750
+ return false
5751
+ }
5752
+
4823
5753
  func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr) (string, []Diagnostic) {
4824
5754
  if ident, ok := expr.Fun.(*ast.Ident); ok && isBuiltinCallTarget(ctx, ident) {
4825
5755
  switch ident.Name {
@@ -4846,6 +5776,22 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
4846
5776
  }
4847
5777
  return o.runtimeOwner.QualifiedHelper(helper) + "(" + strings.Join(args, ", ") + ")", diagnostics
4848
5778
  case "append":
5779
+ if len(expr.Args) > 0 {
5780
+ if slice, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(expr.Args[0])).Underlying().(*types.Slice); ok {
5781
+ for idx := 1; idx < len(args); idx++ {
5782
+ if expr.Ellipsis != token.NoPos && idx == len(args)-1 {
5783
+ continue
5784
+ }
5785
+ args[idx] = o.lowerValueForTargetTypes(
5786
+ ctx,
5787
+ slice.Elem(),
5788
+ ctx.semPkg.source.TypesInfo.TypeOf(expr.Args[idx]),
5789
+ args[idx],
5790
+ false,
5791
+ )
5792
+ }
5793
+ }
5794
+ }
4849
5795
  if expr.Ellipsis != token.NoPos && len(args) > 1 {
4850
5796
  last := len(args) - 1
4851
5797
  spread := args[last]
@@ -4854,7 +5800,13 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
4854
5800
  }
4855
5801
  args[last] = "...(" + spread + " ?? [])"
4856
5802
  }
4857
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperAppend) + "(" + strings.Join(args, ", ") + ")", diagnostics
5803
+ appendHelper := o.runtimeOwner.QualifiedHelper(RuntimeHelperAppend)
5804
+ if len(args) > 0 && args[0] == "null" {
5805
+ if slice, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(expr)).Underlying().(*types.Slice); ok {
5806
+ appendHelper += "<" + o.tsTypeFor(ctx, slice.Elem()) + ">"
5807
+ }
5808
+ }
5809
+ return appendHelper + "(" + strings.Join(args, ", ") + ")", diagnostics
4858
5810
  case "cap":
4859
5811
  if len(expr.Args) == 1 {
4860
5812
  args[0] = o.lowerArrayPointerTarget(ctx, args[0], ctx.semPkg.source.TypesInfo.TypeOf(expr.Args[0]))
@@ -4906,7 +5858,7 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
4906
5858
  if typeParam := receiverTypeParam(selection.Recv()); typeParam != nil {
4907
5859
  receiverExpr, receiverDiagnostics := o.lowerExpr(ctx, fun.X)
4908
5860
  diagnostics = append(diagnostics, receiverDiagnostics...)
4909
- if !signatureHasTypeParam(ctx.signature, typeParam) {
5861
+ if !typeParamInScope(ctx, typeParam) {
4910
5862
  call := receiverExpr + "." + fun.Sel.Name + "(" + strings.Join(args, ", ") + ")"
4911
5863
  return o.awaitCallIfNeeded(ctx, fun, call), diagnostics
4912
5864
  }
@@ -4914,11 +5866,14 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
4914
5866
  call := o.runtimeOwner.QualifiedHelper(RuntimeHelperCallGenericMethod) + "(" + strings.Join(methodArgs, ", ") + ")"
4915
5867
  return o.awaitCallIfNeeded(ctx, fun, call), diagnostics
4916
5868
  }
4917
- receiver := receiverNamedType(selection.Recv())
5869
+ receiver := methodReceiverNamedType(selection.Obj())
5870
+ if receiver == nil {
5871
+ receiver = receiverNamedType(selection.Recv())
5872
+ }
4918
5873
  if namedNonInterfaceNonStructType(receiver) {
4919
5874
  return o.lowerNamedReceiverMethodCall(ctx, fun, args, diagnostics)
4920
5875
  }
4921
- if call, callDiagnostics, ok := o.lowerNilablePointerReceiverMethodCall(ctx, fun, selection, args); ok {
5876
+ if call, callDiagnostics, ok := o.lowerPointerReceiverMethodCall(ctx, fun, selection, args); ok {
4922
5877
  return o.awaitCallIfNeeded(ctx, fun, call), append(diagnostics, callDiagnostics...)
4923
5878
  }
4924
5879
  receiverExpr, receiverDiagnostics := o.lowerMethodReceiverExpr(ctx, fun.X, selection)
@@ -5024,6 +5979,7 @@ func (o *LoweringOwner) lowerCallArgs(
5024
5979
  lowered = o.lowerCallArgForTarget(ctx, arg, params.At(idx).Type(), lowered, overrideCall)
5025
5980
  } else if expr.Ellipsis != token.NoPos && idx == len(expr.Args)-1 {
5026
5981
  lowered = o.lowerCallArgForTarget(ctx, arg, params.At(fixedCount).Type(), lowered, overrideCall)
5982
+ lowered = "...(" + lowered + " ?? [])"
5027
5983
  } else {
5028
5984
  lowered = o.lowerCallArgForTarget(ctx, arg, targetType, lowered, overrideCall)
5029
5985
  }
@@ -5107,19 +6063,41 @@ func (o *LoweringOwner) lowerTupleCallArgs(
5107
6063
  parts = append(parts, converted)
5108
6064
  }
5109
6065
  if !changed {
5110
- return []string{"...(" + value + ")"}, diagnostics, true
6066
+ return []string{"...(" + o.parenthesizedTupleCast(ctx, value, params) + ")"}, diagnostics, true
5111
6067
  }
5112
6068
  temp := ctx.tempName("TupleArg")
5113
6069
  for idx, part := range parts {
5114
6070
  parts[idx] = strings.ReplaceAll(part, "__goscriptTupleArg", temp)
5115
6071
  }
5116
- body := "const " + temp + " = " + value + "; return [" + strings.Join(parts, ", ") + "]"
6072
+ body := "const " + temp + " = " + value + "; return " + o.tupleLiteralCast(ctx, params, parts)
5117
6073
  if strings.Contains(value, "await ") {
5118
6074
  return []string{"...(await (async () => { " + body + " })())"}, diagnostics, true
5119
6075
  }
5120
6076
  return []string{"...(() => { " + body + " })()"}, diagnostics, true
5121
6077
  }
5122
6078
 
6079
+ func (o *LoweringOwner) parenthesizedTupleCast(ctx lowerFileContext, value string, params *types.Tuple) string {
6080
+ if strings.HasPrefix(value, "await ") {
6081
+ return "(" + value + ") as " + o.tupleTypeForParams(ctx, params)
6082
+ }
6083
+ return value + " as " + o.tupleTypeForParams(ctx, params)
6084
+ }
6085
+
6086
+ func (o *LoweringOwner) tupleLiteralCast(ctx lowerFileContext, params *types.Tuple, parts []string) string {
6087
+ return "[" + strings.Join(parts, ", ") + "] as " + o.tupleTypeForParams(ctx, params)
6088
+ }
6089
+
6090
+ func (o *LoweringOwner) tupleTypeForParams(ctx lowerFileContext, params *types.Tuple) string {
6091
+ if params == nil || params.Len() == 0 {
6092
+ return "[]"
6093
+ }
6094
+ parts := make([]string, 0, params.Len())
6095
+ for v := range params.Variables() {
6096
+ parts = append(parts, o.tsTypeFor(ctx, v.Type()))
6097
+ }
6098
+ return "[" + strings.Join(parts, ", ") + "]"
6099
+ }
6100
+
5123
6101
  func (o *LoweringOwner) lowerFixedCallArgs(
5124
6102
  ctx lowerFileContext,
5125
6103
  exprs []ast.Expr,
@@ -5153,7 +6131,7 @@ func (o *LoweringOwner) lowerCallArgForTarget(
5153
6131
  value = o.lowerValueForTarget(ctx, expr, targetType, value)
5154
6132
  sourceType := ctx.semPkg.source.TypesInfo.TypeOf(expr)
5155
6133
  if overrideCall && isNonEmptyInterfaceType(targetType) && (isInterfaceType(sourceType) || isNilableType(sourceType)) {
5156
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + "(" + value + ")"
6134
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValueOrNil) + "(" + value + ")!"
5157
6135
  }
5158
6136
  return value
5159
6137
  }
@@ -5293,7 +6271,7 @@ func (o *LoweringOwner) lowerMakeExpr(ctx lowerFileContext, expr *ast.CallExpr)
5293
6271
  args = append(args, "() => "+o.lowerZeroValueExprFor(ctx, typed.Elem()))
5294
6272
  }
5295
6273
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperMakeSlice) +
5296
- "<" + o.tsTypeFor(ctx, typed.Elem()) + ">(" + strings.Join(args, ", ") + ")", diagnostics
6274
+ "<" + o.tsSliceElemTypeFor(ctx, typed.Elem()) + ">(" + strings.Join(args, ", ") + ")", diagnostics
5297
6275
  case *types.Map:
5298
6276
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperMakeMap) +
5299
6277
  "<" + o.tsTypeFor(ctx, typed.Key()) + ", " + o.tsTypeFor(ctx, typed.Elem()) + ">()", nil
@@ -5321,7 +6299,8 @@ func (o *LoweringOwner) lowerNewExpr(ctx lowerFileContext, expr *ast.CallExpr) (
5321
6299
  if named := namedStructType(typ); named != nil {
5322
6300
  return "new " + o.namedTypeExpr(ctx, named) + "()", nil
5323
6301
  }
5324
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(" + o.lowerZeroValueExprFor(ctx, typ) + ")", nil
6302
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) +
6303
+ "<" + o.tsTypeFor(ctx, typ) + ">(" + o.lowerDeclarationZeroValueExpr(ctx, typ) + ")", nil
5325
6304
  }
5326
6305
 
5327
6306
  func (o *LoweringOwner) lowerConversionExpr(
@@ -5339,12 +6318,17 @@ func (o *LoweringOwner) lowerConversionExpr(
5339
6318
  return value, append(diagnostics, addressDiagnostics...)
5340
6319
  }
5341
6320
  }
6321
+ if helper, addressDiagnostics, ok := o.lowerReflectHeaderPointerConversion(ctx, targetType, expr.Args[0]); ok {
6322
+ return helper, append(diagnostics, addressDiagnostics...)
6323
+ }
6324
+ if helper, addressDiagnostics, ok := o.lowerUnsafeArrayPointerConversion(ctx, targetType, expr.Args[0]); ok {
6325
+ return helper, append(diagnostics, addressDiagnostics...)
6326
+ }
5342
6327
  if isUnsafePointerType(targetType) {
5343
6328
  return "(" + value + " as any)", diagnostics
5344
6329
  }
5345
6330
  if isNilExpr(expr.Args[0]) && isPointerType(targetType) {
5346
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperTypedNil) +
5347
- "(" + strconv.Quote(goRuntimeTypeString(targetType)) + ")", diagnostics
6331
+ return "null", diagnostics
5348
6332
  }
5349
6333
  if isInterfaceType(targetType) {
5350
6334
  return o.lowerValueForTarget(ctx, expr.Args[0], targetType, value), diagnostics
@@ -5402,6 +6386,13 @@ func (o *LoweringOwner) lowerConversionExpr(
5402
6386
  return result, diagnostics
5403
6387
  }
5404
6388
  }
6389
+ if target := pointerToNamedStructType(targetType); target != nil {
6390
+ source := pointerToNamedStructType(sourceType)
6391
+ if source != nil && !types.Identical(target, source) &&
6392
+ types.IdenticalIgnoreTags(target.Underlying(), source.Underlying()) {
6393
+ return "(" + value + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics
6394
+ }
6395
+ }
5405
6396
  if conversion, ok := o.lowerNamedStructConversion(ctx, expr.Args[0], targetType, sourceType, value); ok {
5406
6397
  return renderNamedStructConversion(conversion), diagnostics
5407
6398
  }
@@ -5421,6 +6412,9 @@ func (o *LoweringOwner) lowerConversionExpr(
5421
6412
  return value, diagnostics
5422
6413
  }
5423
6414
  if isNumericType(targetType) {
6415
+ if isFloatType(targetType) {
6416
+ return value, diagnostics
6417
+ }
5424
6418
  if bits, ok := unsignedIntegerBits(targetType); ok {
5425
6419
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
5426
6420
  "(" + value + ", " + strconv.Itoa(bits) + ")", diagnostics
@@ -5440,45 +6434,64 @@ func (o *LoweringOwner) lowerWideIntegerBinaryExpr(ctx lowerFileContext, expr *a
5440
6434
  if !resultWide && !leftWide {
5441
6435
  return "", false
5442
6436
  }
6437
+ signed := isFixedSignedWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr)) ||
6438
+ isFixedSignedWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
5443
6439
  switch expr.Op {
5444
6440
  case token.SHL, token.SHR:
5445
6441
  helper := RuntimeHelperUint64Shr
5446
6442
  if expr.Op == token.SHL {
5447
6443
  helper = RuntimeHelperUint64Shl
5448
6444
  }
6445
+ if signed {
6446
+ helper = RuntimeHelperInt64Shr
6447
+ if expr.Op == token.SHL {
6448
+ helper = RuntimeHelperInt64Shl
6449
+ }
6450
+ }
5449
6451
  if _, ok := constantShiftAmount(ctx, expr.Y); !ok {
5450
6452
  return o.runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")", true
5451
6453
  }
5452
6454
  amount, ok := constantShiftAmount(ctx, expr.Y)
5453
- if ok && amount >= 32 && expr.Op == token.SHL {
6455
+ if ok && amount >= 32 && expr.Op == token.SHL && !signed {
5454
6456
  base := o.lowerWideShiftLeftOperand(ctx, expr.X, left)
5455
6457
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Mul) +
5456
6458
  "(" + base + ", " + shiftMultiplier(amount) + ")", true
5457
6459
  }
5458
6460
  return o.runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")", true
5459
6461
  case token.MUL:
5460
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Mul) + "(" + left + ", " + right + ")", true
6462
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Mul, RuntimeHelperInt64Mul)) + "(" + left + ", " + right + ")", true
6463
+ case token.QUO:
6464
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Div, RuntimeHelperInt64Div)) + "(" + left + ", " + right + ")", true
6465
+ case token.REM:
6466
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Mod, RuntimeHelperInt64Mod)) + "(" + left + ", " + right + ")", true
5461
6467
  case token.ADD:
5462
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Add) + "(" + left + ", " + right + ")", true
6468
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Add, RuntimeHelperInt64Add)) + "(" + left + ", " + right + ")", true
5463
6469
  case token.SUB:
5464
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Sub) + "(" + left + ", " + right + ")", true
6470
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Sub, RuntimeHelperInt64Sub)) + "(" + left + ", " + right + ")", true
5465
6471
  case token.AND:
5466
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64And) + "(" + left + ", " + right + ")", true
6472
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64And, RuntimeHelperInt64And)) + "(" + left + ", " + right + ")", true
5467
6473
  case token.XOR:
5468
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Xor) + "(" + left + ", " + right + ")", true
6474
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Xor, RuntimeHelperInt64Xor)) + "(" + left + ", " + right + ")", true
5469
6475
  case token.OR:
5470
6476
  shift, ok := wideLeftShiftExpr(ctx, expr.X)
5471
- if ok {
6477
+ if ok && !signed {
5472
6478
  if bits, ok := lowIntegerBits(ctx, expr.Y); ok && bits <= shift {
5473
6479
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Add) + "(" + left + ", " + right + ")", true
5474
6480
  }
5475
6481
  }
5476
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Or) + "(" + left + ", " + right + ")", true
6482
+ return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Or, RuntimeHelperInt64Or)) + "(" + left + ", " + right + ")", true
5477
6483
  default:
5478
6484
  return "", false
5479
6485
  }
5480
6486
  }
5481
6487
 
6488
+ func wideIntegerHelper(signed bool, unsigned RuntimeHelper, signedHelper RuntimeHelper) RuntimeHelper {
6489
+ if signed {
6490
+ return signedHelper
6491
+ }
6492
+ return unsigned
6493
+ }
6494
+
5482
6495
  func (o *LoweringOwner) lowerWideShiftLeftOperand(ctx lowerFileContext, expr ast.Expr, fallback string) string {
5483
6496
  call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
5484
6497
  if !ok || len(call.Args) != 1 {
@@ -5647,7 +6660,10 @@ func (o *LoweringOwner) lowerNamedReceiverMethodCall(
5647
6660
  diagnostics []Diagnostic,
5648
6661
  ) (string, []Diagnostic) {
5649
6662
  selection := ctx.semPkg.source.TypesInfo.Selections[selector]
5650
- receiver := receiverNamedType(selection.Recv())
6663
+ receiver := methodReceiverNamedType(selection.Obj())
6664
+ if receiver == nil {
6665
+ receiver = selectedReceiverNamedType(ctx.semPkg.source, selector, selection)
6666
+ }
5651
6667
  receiverExpr, receiverDiagnostics := o.lowerNamedReceiverForMethod(ctx, selector.X, selection)
5652
6668
  diagnostics = append(diagnostics, receiverDiagnostics...)
5653
6669
  allArgs := append([]string{receiverExpr}, args...)
@@ -5655,7 +6671,7 @@ func (o *LoweringOwner) lowerNamedReceiverMethodCall(
5655
6671
  return o.awaitCallIfNeeded(ctx, selector, call), diagnostics
5656
6672
  }
5657
6673
 
5658
- func (o *LoweringOwner) lowerNilablePointerReceiverMethodCall(
6674
+ func (o *LoweringOwner) lowerPointerReceiverMethodCall(
5659
6675
  ctx lowerFileContext,
5660
6676
  selector *ast.SelectorExpr,
5661
6677
  selection *types.Selection,
@@ -5668,9 +6684,6 @@ func (o *LoweringOwner) lowerNilablePointerReceiverMethodCall(
5668
6684
  if method == nil {
5669
6685
  return "", nil, false
5670
6686
  }
5671
- if !methodAllowsNilReceiver(ctx, method) {
5672
- return "", nil, false
5673
- }
5674
6687
  signature, _ := method.Type().(*types.Signature)
5675
6688
  if signature == nil || signature.Recv() == nil {
5676
6689
  return "", nil, false
@@ -5783,8 +6796,12 @@ func (o *LoweringOwner) lowerNamedReceiverForMethod(
5783
6796
  }
5784
6797
  return o.lowerAddressExpr(ctx, expr)
5785
6798
  }
5786
- receiver, diagnostics := o.lowerExpr(ctx, expr)
5787
- if receiverType != nil && isPointerType(ctx.semPkg.source.TypesInfo.TypeOf(expr)) {
6799
+ receiver, diagnostics := o.lowerMethodReceiverExpr(ctx, expr, selection)
6800
+ selectedType := ctx.semPkg.source.TypesInfo.TypeOf(expr)
6801
+ if index := selection.Index(); len(index) > 1 && !o.receiverUsesOverridePackage(selectedType) {
6802
+ selectedType = promotedMethodReceiverType(selectedType, index[:len(index)-1])
6803
+ }
6804
+ if receiverType != nil && isPointerType(selectedType) {
5788
6805
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + "<" + o.tsTypeFor(ctx, receiverType) + ">(" + receiver + ")", diagnostics
5789
6806
  }
5790
6807
  return receiver, diagnostics
@@ -5793,17 +6810,27 @@ func (o *LoweringOwner) lowerNamedReceiverForMethod(
5793
6810
  func (o *LoweringOwner) lowerSelectorExpr(ctx lowerFileContext, expr *ast.SelectorExpr) (string, []Diagnostic) {
5794
6811
  if ident, ok := expr.X.(*ast.Ident); ok {
5795
6812
  if pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName); pkgName != nil {
5796
- if alias := ctx.importNames[pkgName.Name()]; alias != "" {
5797
- return alias + "." + expr.Sel.Name, nil
6813
+ if alias := importAliasForPkgName(ctx, pkgName); alias != "" {
6814
+ value := alias + "." + expr.Sel.Name
6815
+ obj, _ := ctx.semPkg.source.TypesInfo.Uses[expr.Sel].(*types.Var)
6816
+ if obj != nil && packageVarReadNeedsPointerValue(obj.Type()) {
6817
+ value = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
6818
+ "<" + o.tsNonNilTypeFor(ctx, obj.Type()) + ">(" + value + ")"
6819
+ }
6820
+ return value, nil
5798
6821
  }
5799
6822
  }
5800
6823
  }
5801
6824
  if selection := ctx.semPkg.source.TypesInfo.Selections[expr]; selection != nil {
5802
6825
  switch selection.Kind() {
5803
6826
  case types.MethodVal:
5804
- if receiver := receiverNamedType(selection.Recv()); namedNonInterfaceNonStructType(receiver) {
6827
+ namedReceiver := methodReceiverNamedType(selection.Obj())
6828
+ if namedReceiver == nil {
6829
+ namedReceiver = selectedReceiverNamedType(ctx.semPkg.source, expr, selection)
6830
+ }
6831
+ if namedNonInterfaceNonStructType(namedReceiver) {
5805
6832
  receiverExpr, diagnostics := o.lowerNamedReceiverForMethod(ctx, expr.X, selection)
5806
- methodExpr := o.methodFunctionExpr(ctx, receiver, selection.Obj(), expr.Sel.Name)
6833
+ methodExpr := o.methodFunctionExpr(ctx, namedReceiver, selection.Obj(), expr.Sel.Name)
5807
6834
  return o.lowerMethodValueClosure(ctx, selection, receiverExpr, methodExpr, true), diagnostics
5808
6835
  }
5809
6836
  receiver, diagnostics := o.lowerMethodReceiverExpr(ctx, expr.X, selection)
@@ -5818,9 +6845,41 @@ func (o *LoweringOwner) lowerSelectorExpr(ctx lowerFileContext, expr *ast.Select
5818
6845
  }
5819
6846
  }
5820
6847
  left, diagnostics := o.lowerExpr(ctx, expr.X)
6848
+ left = parenthesizeAwaitedExpr(left)
5821
6849
  return left + "." + expr.Sel.Name, diagnostics
5822
6850
  }
5823
6851
 
6852
+ func packageVarSelectorNeedsPointerValue(ctx lowerFileContext, expr ast.Expr) bool {
6853
+ selector, ok := ast.Unparen(expr).(*ast.SelectorExpr)
6854
+ if !ok || ctx.semPkg == nil || ctx.semPkg.source == nil {
6855
+ return false
6856
+ }
6857
+ if selection := ctx.semPkg.source.TypesInfo.Selections[selector]; selection != nil {
6858
+ return false
6859
+ }
6860
+ ident, ok := ast.Unparen(selector.X).(*ast.Ident)
6861
+ if !ok {
6862
+ return false
6863
+ }
6864
+ pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName)
6865
+ if importAliasForPkgName(ctx, pkgName) == "" {
6866
+ return false
6867
+ }
6868
+ obj, _ := ctx.semPkg.source.TypesInfo.Uses[selector.Sel].(*types.Var)
6869
+ return obj != nil && packageVarReadNeedsPointerValue(obj.Type())
6870
+ }
6871
+
6872
+ func packageVarReadNeedsPointerValue(typ types.Type) bool {
6873
+ if typ == nil || isPointerType(typ) {
6874
+ return false
6875
+ }
6876
+ if isStructValueType(typ) {
6877
+ return true
6878
+ }
6879
+ _, ok := types.Unalias(typ).Underlying().(*types.Array)
6880
+ return ok
6881
+ }
6882
+
5824
6883
  func (o *LoweringOwner) packageVarSetterForAssignment(ctx lowerFileContext, expr ast.Expr) (string, bool) {
5825
6884
  if ident, ok := unwrapParenExpr(expr).(*ast.Ident); ok {
5826
6885
  obj, _ := objectForIdent(ctx, ident).(*types.Var)
@@ -5845,7 +6904,7 @@ func (o *LoweringOwner) packageVarSetterForAssignment(ctx lowerFileContext, expr
5845
6904
  if pkgName == nil {
5846
6905
  return "", false
5847
6906
  }
5848
- alias := ctx.importNames[pkgName.Name()]
6907
+ alias := importAliasForPkgName(ctx, pkgName)
5849
6908
  if alias == "" {
5850
6909
  return "", false
5851
6910
  }
@@ -5856,6 +6915,36 @@ func (o *LoweringOwner) packageVarSetterForAssignment(ctx lowerFileContext, expr
5856
6915
  return alias + "." + packageVarSetterName(selector.Sel.Name), true
5857
6916
  }
5858
6917
 
6918
+ func (o *LoweringOwner) packageVarAssignmentValue(
6919
+ ctx lowerFileContext,
6920
+ lhs ast.Expr,
6921
+ targetType types.Type,
6922
+ right string,
6923
+ tok token.Token,
6924
+ ) (string, bool) {
6925
+ if tok == token.ASSIGN {
6926
+ return right, true
6927
+ }
6928
+ left, diagnostics := o.lowerExpr(ctx, lhs)
6929
+ if len(diagnostics) != 0 {
6930
+ return "", false
6931
+ }
6932
+ if tok == token.AND_NOT_ASSIGN {
6933
+ return left + " & ~(" + right + ")", true
6934
+ }
6935
+ if helper, ok := wideIntegerAssignHelper(targetType, tok); ok {
6936
+ return o.runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")", true
6937
+ }
6938
+ if value, ok := integerQuotientAssignValueExpr(targetType, left, right, tok); ok {
6939
+ return value, true
6940
+ }
6941
+ op := tok.String()
6942
+ if before, ok := strings.CutSuffix(op, "="); ok {
6943
+ op = before
6944
+ }
6945
+ return left + " " + op + " " + right, true
6946
+ }
6947
+
5859
6948
  func (o *LoweringOwner) tsPackageVarSetterValueTypeFor(ctx lowerFileContext, typ types.Type) string {
5860
6949
  if signature := unnamedSignatureForType(typ); signature != nil {
5861
6950
  return o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
@@ -5870,25 +6959,28 @@ func (o *LoweringOwner) lowerFieldSelectionExpr(
5870
6959
  address bool,
5871
6960
  ) (string, []Diagnostic) {
5872
6961
  receiver, diagnostics := o.lowerFieldReceiverExpr(ctx, expr.X)
6962
+ receiver = parenthesizeAwaitedExpr(receiver)
5873
6963
  index := selection.Index()
5874
6964
  if len(index) == 0 {
6965
+ fieldName := tsStructFieldName(expr.Sel.Name, 0)
5875
6966
  if address {
5876
- return o.lowerFieldAddressExpr(ctx, receiver, ctx.semPkg.source.TypesInfo.TypeOf(expr.X), expr.Sel.Name), diagnostics
6967
+ return o.lowerFieldAddressExpr(ctx, receiver, ctx.semPkg.source.TypesInfo.TypeOf(expr.X), fieldName), diagnostics
5877
6968
  }
5878
- return receiver + "." + expr.Sel.Name, diagnostics
6969
+ return receiver + "." + fieldName, diagnostics
5879
6970
  }
5880
6971
 
5881
6972
  typ := derefPointerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
5882
6973
  for idx, fieldIndex := range index {
5883
6974
  structType := structUnderlyingType(typ)
5884
6975
  if structType == nil || fieldIndex < 0 || fieldIndex >= structType.NumFields() {
6976
+ fieldName := tsStructFieldName(expr.Sel.Name, 0)
5885
6977
  if address {
5886
- return receiver + "._fields." + expr.Sel.Name, diagnostics
6978
+ return receiver + "._fields." + fieldName, diagnostics
5887
6979
  }
5888
- return receiver + "." + expr.Sel.Name, diagnostics
6980
+ return receiver + "." + fieldName, diagnostics
5889
6981
  }
5890
6982
  field := structType.Field(fieldIndex)
5891
- name := field.Name()
6983
+ name := tsStructFieldName(field.Name(), fieldIndex)
5892
6984
  if idx == len(index)-1 {
5893
6985
  if address {
5894
6986
  return o.lowerFieldAddressExpr(ctx, receiver, typ, name), diagnostics
@@ -5906,9 +6998,9 @@ func (o *LoweringOwner) lowerFieldSelectionExpr(
5906
6998
  }
5907
6999
 
5908
7000
  if address {
5909
- return o.lowerFieldAddressExpr(ctx, receiver, typ, expr.Sel.Name), diagnostics
7001
+ return o.lowerFieldAddressExpr(ctx, receiver, typ, tsStructFieldName(expr.Sel.Name, 0)), diagnostics
5910
7002
  }
5911
- return receiver + "." + expr.Sel.Name, diagnostics
7003
+ return receiver + "." + tsStructFieldName(expr.Sel.Name, 0), diagnostics
5912
7004
  }
5913
7005
 
5914
7006
  func (o *LoweringOwner) lowerFieldAddressExpr(ctx lowerFileContext, receiver string, typ types.Type, fieldName string) string {
@@ -5980,9 +7072,11 @@ func (o *LoweringOwner) lowerFieldReceiverExpr(ctx lowerFileContext, expr ast.Ex
5980
7072
  return o.lowerPointerValueExpr(ctx, expr)
5981
7073
  }
5982
7074
  value, diagnostics := o.lowerExpr(ctx, expr)
7075
+ value = parenthesizeAwaitedExpr(value)
5983
7076
  if obj := objectForValueExpr(ctx, expr); obj != nil &&
5984
- ctx.model.needsVarRef[obj] &&
7077
+ objectNeedsVarRef(ctx, obj) &&
5985
7078
  isStructValueType(obj.Type()) &&
7079
+ !packageVarSelectorNeedsPointerValue(ctx, expr) &&
5986
7080
  fieldReceiverNeedsVarRefValue(ctx, expr, obj) {
5987
7081
  return value + ".value", diagnostics
5988
7082
  }
@@ -5993,7 +7087,16 @@ func fieldReceiverNeedsVarRefValue(ctx lowerFileContext, expr ast.Expr, obj type
5993
7087
  if _, ok := expr.(*ast.Ident); !ok {
5994
7088
  return true
5995
7089
  }
5996
- return ctx.localAliases[obj] != "" || ctx.identAliases[obj] != ""
7090
+ if ctx.identAliases[obj] != "" {
7091
+ return !ctx.identAliasRefs[obj]
7092
+ }
7093
+ if ctx.localAliases[obj] != "" {
7094
+ if varObj, ok := obj.(*types.Var); ok && packageVarReadNeedsPointerValue(varObj.Type()) {
7095
+ return false
7096
+ }
7097
+ return !ctx.lazyPackageVars[obj]
7098
+ }
7099
+ return false
5997
7100
  }
5998
7101
 
5999
7102
  func (o *LoweringOwner) lowerMethodReceiverExpr(
@@ -6016,14 +7119,24 @@ func (o *LoweringOwner) lowerMethodReceiverExpr(
6016
7119
  receiver, diagnostics = o.lowerPointerValueExpr(ctx, expr)
6017
7120
  } else {
6018
7121
  receiver, diagnostics = o.lowerExpr(ctx, expr)
7122
+ receiver = parenthesizeAwaitedExpr(receiver)
6019
7123
  }
6020
7124
  receiverType := ctx.semPkg.source.TypesInfo.TypeOf(expr)
7125
+ if !receiverPointer {
7126
+ if obj := objectForValueExpr(ctx, expr); obj != nil &&
7127
+ objectNeedsVarRef(ctx, obj) &&
7128
+ isStructValueType(obj.Type()) &&
7129
+ !packageVarSelectorNeedsPointerValue(ctx, expr) &&
7130
+ fieldReceiverNeedsVarRefValue(ctx, expr, obj) {
7131
+ receiver += ".value"
7132
+ }
7133
+ }
6021
7134
  if index := selection.Index(); len(index) > 1 && !o.receiverUsesOverridePackage(receiverType) {
6022
7135
  receiver, receiverType = o.lowerPromotedMethodReceiver(ctx, receiver, receiverType, index[:len(index)-1])
6023
7136
  }
6024
7137
  if receiverPointer {
6025
7138
  if obj := objectForValueExpr(ctx, expr); obj != nil &&
6026
- ctx.model.needsVarRef[obj] &&
7139
+ objectNeedsVarRef(ctx, obj) &&
6027
7140
  isStructValueType(obj.Type()) &&
6028
7141
  fieldReceiverNeedsVarRefValue(ctx, expr, obj) {
6029
7142
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
@@ -6074,16 +7187,38 @@ func (o *LoweringOwner) lowerPromotedMethodReceiver(
6074
7187
  return receiver, typ
6075
7188
  }
6076
7189
 
7190
+ func promotedMethodReceiverType(typ types.Type, index []int) types.Type {
7191
+ typ = derefPointerType(typ)
7192
+ for _, fieldIndex := range index {
7193
+ structType := structUnderlyingType(typ)
7194
+ if structType == nil || fieldIndex < 0 || fieldIndex >= structType.NumFields() {
7195
+ return typ
7196
+ }
7197
+ typ = structType.Field(fieldIndex).Type()
7198
+ if pointer, ok := types.Unalias(typ).Underlying().(*types.Pointer); ok {
7199
+ typ = pointer.Elem()
7200
+ }
7201
+ }
7202
+ return typ
7203
+ }
7204
+
6077
7205
  func (o *LoweringOwner) lowerAssignmentTarget(
6078
7206
  ctx lowerFileContext,
6079
7207
  expr ast.Expr,
6080
7208
  declare bool,
6081
7209
  ) (string, []Diagnostic) {
6082
- switch typed := expr.(type) {
7210
+ switch typed := unwrapParenExpr(expr).(type) {
6083
7211
  case *ast.Ident:
6084
7212
  if declare {
6085
7213
  return o.lowerIdent(ctx, typed, true), nil
6086
7214
  }
7215
+ if obj := objectForIdent(ctx, typed); obj != nil && ctx.lazyPackageVars[obj] {
7216
+ target := o.lowerIdent(ctx, typed, true)
7217
+ if ctx.model.needsVarRef[obj] {
7218
+ target += ".value"
7219
+ }
7220
+ return target, nil
7221
+ }
6087
7222
  return o.lowerIdent(ctx, typed, false), nil
6088
7223
  case *ast.StarExpr:
6089
7224
  return o.lowerPointerValueExpr(ctx, typed.X)
@@ -6093,7 +7228,10 @@ func (o *LoweringOwner) lowerAssignmentTarget(
6093
7228
  }
6094
7229
 
6095
7230
  func (o *LoweringOwner) lowerAddressExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
6096
- switch typed := expr.(type) {
7231
+ if value, ok := o.lowerPackageVarAddressExpr(ctx, expr); ok {
7232
+ return value, nil
7233
+ }
7234
+ switch typed := unwrapParenExpr(expr).(type) {
6097
7235
  case *ast.Ident:
6098
7236
  return o.lowerIdent(ctx, typed, true), nil
6099
7237
  case *ast.CompositeLit:
@@ -6115,6 +7253,55 @@ func (o *LoweringOwner) lowerAddressExpr(ctx lowerFileContext, expr ast.Expr) (s
6115
7253
  }
6116
7254
  }
6117
7255
 
7256
+ func (o *LoweringOwner) lowerPackageVarAddressExpr(ctx lowerFileContext, expr ast.Expr) (string, bool) {
7257
+ switch typed := unwrapParenExpr(expr).(type) {
7258
+ case *ast.Ident:
7259
+ obj, _ := objectForIdent(ctx, typed).(*types.Var)
7260
+ if obj == nil || !objectNeedsVarRef(ctx, obj) {
7261
+ return "", false
7262
+ }
7263
+ return o.lowerIdent(ctx, typed, true), true
7264
+ case *ast.SelectorExpr:
7265
+ if selection := ctx.semPkg.source.TypesInfo.Selections[typed]; selection != nil {
7266
+ return "", false
7267
+ }
7268
+ ident, ok := unwrapParenExpr(typed.X).(*ast.Ident)
7269
+ if !ok {
7270
+ return "", false
7271
+ }
7272
+ pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName)
7273
+ if pkgName == nil {
7274
+ return "", false
7275
+ }
7276
+ alias := importAliasForPkgName(ctx, pkgName)
7277
+ if alias == "" {
7278
+ return "", false
7279
+ }
7280
+ obj, _ := ctx.semPkg.source.TypesInfo.Uses[typed.Sel].(*types.Var)
7281
+ if obj == nil || !objectNeedsVarRef(ctx, obj) {
7282
+ return "", false
7283
+ }
7284
+ return alias + "." + typed.Sel.Name, true
7285
+ default:
7286
+ return "", false
7287
+ }
7288
+ }
7289
+
7290
+ func importAliasForPkgName(ctx lowerFileContext, pkgName *types.PkgName) string {
7291
+ if pkgName == nil {
7292
+ return ""
7293
+ }
7294
+ if alias := ctx.importObjects[pkgName]; alias != "" {
7295
+ return alias
7296
+ }
7297
+ if imported := pkgName.Imported(); imported != nil {
7298
+ if alias := ctx.importPaths[imported.Path()]; alias != "" {
7299
+ return alias
7300
+ }
7301
+ }
7302
+ return ctx.importNames[pkgName.Name()]
7303
+ }
7304
+
6118
7305
  func (o *LoweringOwner) lowerIndexAddressExpr(ctx lowerFileContext, expr *ast.IndexExpr) (string, []Diagnostic) {
6119
7306
  target, targetDiagnostics := o.lowerExpr(ctx, expr.X)
6120
7307
  index, indexDiagnostics := o.lowerExpr(ctx, expr.Index)
@@ -6160,57 +7347,251 @@ func (o *LoweringOwner) lowerIndexAddressIntegerExpr(
6160
7347
  if !ok || address.Op != token.AND {
6161
7348
  return "", nil, false
6162
7349
  }
6163
- indexExpr, ok := unwrapParenExpr(address.X).(*ast.IndexExpr)
7350
+ indexExpr, ok := unwrapParenExpr(address.X).(*ast.IndexExpr)
7351
+ if !ok {
7352
+ return "", nil, false
7353
+ }
7354
+ target, targetDiagnostics := o.lowerExpr(ctx, indexExpr.X)
7355
+ index, indexDiagnostics := o.lowerExpr(ctx, indexExpr.Index)
7356
+ diagnostics := append(targetDiagnostics, indexDiagnostics...)
7357
+ targetType := ctx.semPkg.source.TypesInfo.TypeOf(indexExpr.X)
7358
+ if isStringType(targetType) || isMapType(targetType) {
7359
+ return "", diagnostics, false
7360
+ }
7361
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperIndexAddress) +
7362
+ "(" + o.lowerIndexTarget(ctx, target, targetType) + ", " + index + ")", diagnostics, true
7363
+ }
7364
+
7365
+ func (o *LoweringOwner) lowerPointerValueExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
7366
+ if value, diagnostics, ok := o.lowerUnsafeStringPointerValue(ctx, expr); ok {
7367
+ return value, diagnostics
7368
+ }
7369
+ if value, diagnostics, ok := o.lowerUnsafeStringByteSlicePointerValue(ctx, expr); ok {
7370
+ return value, diagnostics
7371
+ }
7372
+ base, diagnostics := o.lowerExpr(ctx, expr)
7373
+ typeArg := ""
7374
+ if pointer, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(expr)).Underlying().(*types.Pointer); ok {
7375
+ typeArg = "<" + o.tsTypeFor(ctx, pointer.Elem()) + ">"
7376
+ }
7377
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + typeArg + "(" + base + ")", diagnostics
7378
+ }
7379
+
7380
+ func (o *LoweringOwner) lowerUnsafeStringPointerValue(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic, bool) {
7381
+ call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
7382
+ if !ok || len(call.Args) != 1 {
7383
+ return "", nil, false
7384
+ }
7385
+ targetType := typeFromExpr(ctx, call.Fun)
7386
+ if targetType == nil {
7387
+ return "", nil, false
7388
+ }
7389
+ targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
7390
+ if targetPointer == nil || !isStringType(targetPointer.Elem()) {
7391
+ return "", nil, false
7392
+ }
7393
+ unsafeCall, ok := unwrapParenExpr(call.Args[0]).(*ast.CallExpr)
7394
+ unsafeTargetType := typeFromExpr(ctx, unsafeCall.Fun)
7395
+ if !ok || len(unsafeCall.Args) != 1 || unsafeTargetType == nil || !isUnsafePointerType(unsafeTargetType) {
7396
+ return "", nil, false
7397
+ }
7398
+ address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
7399
+ if !ok || address.Op != token.AND || !isByteSliceType(ctx.semPkg.source.TypesInfo.TypeOf(address.X)) {
7400
+ return "", nil, false
7401
+ }
7402
+ value, diagnostics := o.lowerExpr(ctx, address.X)
7403
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperBytesToString) + "(" + value + ")", diagnostics, true
7404
+ }
7405
+
7406
+ func (o *LoweringOwner) lowerUnsafeStringByteSlicePointerValue(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic, bool) {
7407
+ call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
7408
+ if !ok || len(call.Args) != 1 {
7409
+ return "", nil, false
7410
+ }
7411
+ targetType := typeFromExpr(ctx, call.Fun)
7412
+ if targetType == nil {
7413
+ return "", nil, false
7414
+ }
7415
+ targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
7416
+ if targetPointer == nil || !isByteSliceType(targetPointer.Elem()) {
7417
+ return "", nil, false
7418
+ }
7419
+ unsafeCall, ok := unwrapParenExpr(call.Args[0]).(*ast.CallExpr)
7420
+ unsafeTargetType := typeFromExpr(ctx, unsafeCall.Fun)
7421
+ if !ok || len(unsafeCall.Args) != 1 || unsafeTargetType == nil || !isUnsafePointerType(unsafeTargetType) {
7422
+ return "", nil, false
7423
+ }
7424
+ address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
7425
+ if !ok || address.Op != token.AND {
7426
+ return "", nil, false
7427
+ }
7428
+ source, ok := localStringSliceHeaderSource(ctx, address.X)
7429
+ if !ok {
7430
+ return "", nil, false
7431
+ }
7432
+ value, diagnostics := o.lowerExpr(ctx, source)
7433
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperStringToBytes) + "(" + value + ")", diagnostics, true
7434
+ }
7435
+
7436
+ func (o *LoweringOwner) lowerReflectHeaderPointerConversion(
7437
+ ctx lowerFileContext,
7438
+ targetType types.Type,
7439
+ expr ast.Expr,
7440
+ ) (string, []Diagnostic, bool) {
7441
+ targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
7442
+ if targetPointer == nil {
7443
+ return "", nil, false
7444
+ }
7445
+ header, _ := types.Unalias(targetPointer.Elem()).(*types.Named)
7446
+ if header == nil || header.Obj() == nil || header.Obj().Pkg() == nil || header.Obj().Pkg().Path() != "reflect" {
7447
+ return "", nil, false
7448
+ }
7449
+ unsafeCall, ok := unwrapParenExpr(expr).(*ast.CallExpr)
7450
+ if !ok || len(unsafeCall.Args) != 1 || !isUnsafePointerType(typeFromExpr(ctx, unsafeCall.Fun)) {
7451
+ return "", nil, false
7452
+ }
7453
+ address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
7454
+ if !ok || address.Op != token.AND {
7455
+ return "", nil, false
7456
+ }
7457
+ switch header.Obj().Name() {
7458
+ case "StringHeader":
7459
+ if !isStringType(ctx.semPkg.source.TypesInfo.TypeOf(address.X)) {
7460
+ return "", nil, false
7461
+ }
7462
+ value, diagnostics := o.lowerAddressedValueRef(ctx, address.X)
7463
+ helper := o.runtimeOwner.QualifiedHelper(RuntimeHelperStringHeaderRef) + "(" + value + ")"
7464
+ return "(" + helper + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics, true
7465
+ case "SliceHeader":
7466
+ if !isByteSliceType(ctx.semPkg.source.TypesInfo.TypeOf(address.X)) {
7467
+ return "", nil, false
7468
+ }
7469
+ value, diagnostics := o.lowerAddressedValueRef(ctx, address.X)
7470
+ helper := o.runtimeOwner.QualifiedHelper(RuntimeHelperSliceHeaderRef) + "(" + value + ")"
7471
+ return "(" + helper + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics, true
7472
+ default:
7473
+ return "", nil, false
7474
+ }
7475
+ }
7476
+
7477
+ func (o *LoweringOwner) lowerUnsafeArrayPointerConversion(
7478
+ ctx lowerFileContext,
7479
+ targetType types.Type,
7480
+ expr ast.Expr,
7481
+ ) (string, []Diagnostic, bool) {
7482
+ targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
7483
+ if targetPointer == nil {
7484
+ return "", nil, false
7485
+ }
7486
+ array, _ := types.Unalias(targetPointer.Elem()).Underlying().(*types.Array)
7487
+ if array == nil {
7488
+ return "", nil, false
7489
+ }
7490
+ unsafeCall, ok := unwrapParenExpr(expr).(*ast.CallExpr)
7491
+ if !ok || len(unsafeCall.Args) != 1 || !isUnsafePointerType(typeFromExpr(ctx, unsafeCall.Fun)) {
7492
+ return "", nil, false
7493
+ }
7494
+ address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
7495
+ if !ok || address.Op != token.AND {
7496
+ return "", nil, false
7497
+ }
7498
+ index, ok := unwrapParenExpr(address.X).(*ast.IndexExpr)
6164
7499
  if !ok {
6165
7500
  return "", nil, false
6166
7501
  }
6167
- target, targetDiagnostics := o.lowerExpr(ctx, indexExpr.X)
6168
- index, indexDiagnostics := o.lowerExpr(ctx, indexExpr.Index)
6169
- diagnostics := append(targetDiagnostics, indexDiagnostics...)
6170
- targetType := ctx.semPkg.source.TypesInfo.TypeOf(indexExpr.X)
6171
- if isStringType(targetType) || isMapType(targetType) {
6172
- return "", diagnostics, false
7502
+ ref, diagnostics := o.lowerAddressExpr(ctx, index)
7503
+ helper := o.runtimeOwner.QualifiedHelper(RuntimeHelperArrayPointerFromIndexRef) +
7504
+ "<" + o.tsTypeFor(ctx, array.Elem()) + ">(" + ref + ", " + strconv.FormatInt(array.Len(), 10) + ")"
7505
+ return "(" + helper + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics, true
7506
+ }
7507
+
7508
+ func (o *LoweringOwner) lowerAddressedValueRef(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
7509
+ if ident, ok := unwrapParenExpr(expr).(*ast.Ident); ok {
7510
+ if obj := objectForIdent(ctx, ident); obj != nil && ctx.model.needsVarRef[obj] {
7511
+ return o.lowerIdent(ctx, ident, true), nil
7512
+ }
6173
7513
  }
6174
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperIndexAddress) +
6175
- "(" + o.lowerIndexTarget(ctx, target, targetType) + ", " + index + ")", diagnostics, true
7514
+ value, diagnostics := o.lowerExpr(ctx, expr)
7515
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(" + value + ")", diagnostics
6176
7516
  }
6177
7517
 
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
7518
+ func localStringSliceHeaderSource(ctx lowerFileContext, expr ast.Expr) (ast.Expr, bool) {
7519
+ lit, ok := unwrapParenExpr(expr).(*ast.CompositeLit)
7520
+ if !ok {
7521
+ return nil, false
6181
7522
  }
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()) + ">"
7523
+ structType, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(lit)).Underlying().(*types.Struct)
7524
+ if !ok || structType.NumFields() != 2 {
7525
+ return nil, false
6186
7526
  }
6187
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + typeArg + "(" + base + ")", diagnostics
7527
+ if !isStringType(structType.Field(0).Type()) || !isIntegerType(structType.Field(1).Type()) {
7528
+ return nil, false
7529
+ }
7530
+ var source ast.Expr
7531
+ var capacity ast.Expr
7532
+ for idx, elt := range lit.Elts {
7533
+ fieldIndex := idx
7534
+ valueExpr := elt
7535
+ if keyed, ok := elt.(*ast.KeyValueExpr); ok {
7536
+ valueExpr = keyed.Value
7537
+ ident, ok := keyed.Key.(*ast.Ident)
7538
+ if !ok {
7539
+ return nil, false
7540
+ }
7541
+ fieldIndex = -1
7542
+ for index := range structType.NumFields() {
7543
+ if structType.Field(index).Name() == ident.Name {
7544
+ fieldIndex = index
7545
+ break
7546
+ }
7547
+ }
7548
+ if fieldIndex < 0 {
7549
+ return nil, false
7550
+ }
7551
+ }
7552
+ switch fieldIndex {
7553
+ case 0:
7554
+ source = valueExpr
7555
+ case 1:
7556
+ capacity = valueExpr
7557
+ }
7558
+ }
7559
+ if source == nil || capacity == nil {
7560
+ return nil, false
7561
+ }
7562
+ if !isStringType(ctx.semPkg.source.TypesInfo.TypeOf(source)) ||
7563
+ !isIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(capacity)) {
7564
+ return nil, false
7565
+ }
7566
+ if !isLenCallOfExpr(ctx, capacity, source) {
7567
+ return nil, false
7568
+ }
7569
+ return source, true
6188
7570
  }
6189
7571
 
6190
- func (o *LoweringOwner) lowerUnsafeStringPointerValue(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic, bool) {
7572
+ func isLenCallOfExpr(ctx lowerFileContext, expr ast.Expr, target ast.Expr) bool {
6191
7573
  call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
6192
7574
  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
7575
+ return false
6198
7576
  }
6199
- targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
6200
- if targetPointer == nil || !isStringType(targetPointer.Elem()) {
6201
- return "", nil, false
7577
+ ident, ok := unwrapParenExpr(call.Fun).(*ast.Ident)
7578
+ if !ok || ident.Name != "len" {
7579
+ return false
6202
7580
  }
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
7581
+ if objectForIdent(ctx, ident) != types.Universe.Lookup("len") {
7582
+ return false
6207
7583
  }
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
7584
+ return sameLoweredSourceExpr(ctx, call.Args[0], target)
7585
+ }
7586
+
7587
+ func sameLoweredSourceExpr(ctx lowerFileContext, left ast.Expr, right ast.Expr) bool {
7588
+ left = unwrapParenExpr(left)
7589
+ right = unwrapParenExpr(right)
7590
+ if leftIdent, ok := left.(*ast.Ident); ok {
7591
+ rightIdent, ok := right.(*ast.Ident)
7592
+ return ok && objectForIdent(ctx, leftIdent) == objectForIdent(ctx, rightIdent)
6211
7593
  }
6212
- value, diagnostics := o.lowerExpr(ctx, address.X)
6213
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperBytesToString) + "(" + value + ")", diagnostics, true
7594
+ return false
6214
7595
  }
6215
7596
 
6216
7597
  func (o *LoweringOwner) lowerPointerStorageExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
@@ -6362,6 +7743,13 @@ func (o *LoweringOwner) lowerCompositeLit(
6362
7743
  lit *ast.CompositeLit,
6363
7744
  markStruct bool,
6364
7745
  ) (string, []Diagnostic) {
7746
+ if len(lit.Elts) == 0 {
7747
+ if typeParam, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(lit)).(*types.TypeParam); ok {
7748
+ if typeParamInScope(ctx, typeParam) {
7749
+ return o.lowerDeclarationZeroValueExpr(ctx, typeParam), nil
7750
+ }
7751
+ }
7752
+ }
6365
7753
  named := namedStructType(ctx.semPkg.source.TypesInfo.TypeOf(lit))
6366
7754
  if named != nil {
6367
7755
  return o.lowerStructCompositeLit(ctx, lit, named, markStruct)
@@ -6402,6 +7790,7 @@ func (o *LoweringOwner) lowerStructCompositeLit(
6402
7790
  ) (string, []Diagnostic) {
6403
7791
  structType, _ := named.Underlying().(*types.Struct)
6404
7792
  fields := make([]string, 0, len(lit.Elts))
7793
+ var prelude []string
6405
7794
  var diagnostics []Diagnostic
6406
7795
  for idx, elt := range lit.Elts {
6407
7796
  fieldName := ""
@@ -6410,9 +7799,13 @@ func (o *LoweringOwner) lowerStructCompositeLit(
6410
7799
  if keyed, ok := elt.(*ast.KeyValueExpr); ok {
6411
7800
  valueExpr = keyed.Value
6412
7801
  if ident, ok := keyed.Key.(*ast.Ident); ok {
6413
- fieldName = ident.Name
6414
- if field := fieldByName(structType, fieldName); field != nil {
6415
- fieldType = field.Type()
7802
+ for index := range structType.NumFields() {
7803
+ field := structType.Field(index)
7804
+ if field.Name() == ident.Name {
7805
+ fieldName = tsStructFieldName(field.Name(), index)
7806
+ fieldType = field.Type()
7807
+ break
7808
+ }
6416
7809
  }
6417
7810
  }
6418
7811
  } else if idx < structType.NumFields() {
@@ -6427,6 +7820,11 @@ func (o *LoweringOwner) lowerStructCompositeLit(
6427
7820
  value, valueDiagnostics := o.lowerExpr(ctx, valueExpr)
6428
7821
  diagnostics = append(diagnostics, valueDiagnostics...)
6429
7822
  value = o.lowerValueForTarget(ctx, valueExpr, fieldType, value)
7823
+ if compositeLiteralFieldNeedsPreEval(ctx, valueExpr) {
7824
+ temp := ctx.tempName("LiteralField")
7825
+ prelude = append(prelude, "const "+temp+" = "+value)
7826
+ value = temp
7827
+ }
6430
7828
  fields = append(fields, fieldName+": "+value)
6431
7829
  }
6432
7830
 
@@ -6437,9 +7835,30 @@ func (o *LoweringOwner) lowerStructCompositeLit(
6437
7835
  if markStruct {
6438
7836
  expr = o.runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue) + "(" + expr + ")"
6439
7837
  }
7838
+ if len(prelude) != 0 {
7839
+ body := strings.Join(prelude, "; ") + "; return " + expr
7840
+ if strings.Contains(body, "await ") {
7841
+ return "(await (async () => { " + body + " })())", diagnostics
7842
+ }
7843
+ return "(() => { " + body + " })()", diagnostics
7844
+ }
6440
7845
  return expr, diagnostics
6441
7846
  }
6442
7847
 
7848
+ func compositeLiteralFieldNeedsPreEval(ctx lowerFileContext, expr ast.Expr) bool {
7849
+ switch typed := unwrapParenExpr(expr).(type) {
7850
+ case *ast.CallExpr:
7851
+ if ident, ok := typed.Fun.(*ast.Ident); ok && isBuiltinCallTarget(ctx, ident) {
7852
+ return false
7853
+ }
7854
+ return typeFromExpr(ctx, typed.Fun) == nil
7855
+ case *ast.UnaryExpr:
7856
+ return typed.Op == token.ARROW
7857
+ default:
7858
+ return false
7859
+ }
7860
+ }
7861
+
6443
7862
  func (o *LoweringOwner) lowerAnonymousStructCompositeLit(
6444
7863
  ctx lowerFileContext,
6445
7864
  lit *ast.CompositeLit,
@@ -6460,10 +7879,10 @@ func (o *LoweringOwner) lowerAnonymousStructCompositeLit(
6460
7879
  if keyed, ok := elt.(*ast.KeyValueExpr); ok {
6461
7880
  valueExpr = keyed.Value
6462
7881
  if ident, ok := keyed.Key.(*ast.Ident); ok {
6463
- fieldName = ident.Name
6464
7882
  for index := range structType.NumFields() {
6465
7883
  field := structType.Field(index)
6466
- if field.Name() == fieldName {
7884
+ if field.Name() == ident.Name {
7885
+ fieldName = tsStructFieldName(field.Name(), index)
6467
7886
  fieldIndex = index
6468
7887
  fieldType = field.Type()
6469
7888
  break
@@ -6571,7 +7990,7 @@ func (o *LoweringOwner) lowerSliceCompositeLit(
6571
7990
  nextIndex = index + 1
6572
7991
  }
6573
7992
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperArrayToSlice) +
6574
- "<" + o.tsTypeFor(ctx, slice.Elem()) + ">([" + strings.Join(values, ", ") + "])", diagnostics
7993
+ "<" + o.tsSliceElemTypeFor(ctx, slice.Elem()) + ">([" + strings.Join(values, ", ") + "])", diagnostics
6575
7994
  }
6576
7995
 
6577
7996
  func (o *LoweringOwner) lowerMapCompositeLit(
@@ -6602,7 +8021,7 @@ func (o *LoweringOwner) lowerTypeAssertExpr(ctx lowerFileContext, expr *ast.Type
6602
8021
  targetType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Type)
6603
8022
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperMustTypeAssert) +
6604
8023
  "<" + o.tsTypeAssertionTypeFor(ctx, targetType) + ">(" +
6605
- value + ", " + o.runtimeTypeInfoExpr(targetType) + ")", diagnostics
8024
+ value + ", " + o.runtimeTypeAssertInfoExpr(ctx, targetType) + ")", diagnostics
6606
8025
  }
6607
8026
 
6608
8027
  func (o *LoweringOwner) lowerTupleExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
@@ -6612,7 +8031,7 @@ func (o *LoweringOwner) lowerTupleExpr(ctx lowerFileContext, expr ast.Expr) (str
6612
8031
  targetType := ctx.semPkg.source.TypesInfo.TypeOf(typed.Type)
6613
8032
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperTypeAssertTuple) +
6614
8033
  "<" + o.tsTypeAssertionTypeFor(ctx, targetType) + ">(" +
6615
- value + ", " + o.runtimeTypeInfoExpr(targetType) + ")", diagnostics
8034
+ value + ", " + o.runtimeTypeAssertInfoExpr(ctx, targetType) + ")", diagnostics
6616
8035
  case *ast.IndexExpr:
6617
8036
  if isMapType(ctx.semPkg.source.TypesInfo.TypeOf(typed.X)) {
6618
8037
  target, targetDiagnostics := o.lowerExpr(ctx, typed.X)
@@ -6644,6 +8063,9 @@ func (o *LoweringOwner) lowerValueForTarget(
6644
8063
  ) string {
6645
8064
  sourceType := ctx.semPkg.source.TypesInfo.TypeOf(expr)
6646
8065
  if isComplexType(targetType) {
8066
+ if isComplexType(sourceType) {
8067
+ return value
8068
+ }
6647
8069
  if isRealNumericConstantExpr(ctx, expr) {
6648
8070
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperComplex) + "(" + value + ", 0)"
6649
8071
  }
@@ -6697,6 +8119,14 @@ func isRealNumericConstantExpr(ctx lowerFileContext, expr ast.Expr) bool {
6697
8119
  }
6698
8120
  }
6699
8121
 
8122
+ func lowerPrefixUnaryExpr(op token.Token, value string) string {
8123
+ prefix := op.String()
8124
+ if (op == token.SUB && strings.HasPrefix(value, "-")) || (op == token.ADD && strings.HasPrefix(value, "+")) {
8125
+ return prefix + "(" + value + ")"
8126
+ }
8127
+ return prefix + value
8128
+ }
8129
+
6700
8130
  func (o *LoweringOwner) lowerValueForTargetTypes(
6701
8131
  ctx lowerFileContext,
6702
8132
  targetType types.Type,
@@ -6704,6 +8134,9 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
6704
8134
  value string,
6705
8135
  cloneStructValue bool,
6706
8136
  ) string {
8137
+ if targetType == nil || sourceType == nil {
8138
+ return value
8139
+ }
6707
8140
  if isFunctionType(targetType) && isUntypedNilType(sourceType) {
6708
8141
  return "(" + value + " as " + o.tsTypeFor(ctx, targetType) + ")"
6709
8142
  }
@@ -6734,6 +8167,15 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
6734
8167
  return o.lowerStructClone(value)
6735
8168
  }
6736
8169
  if isIntegerType(targetType) && isIntegerType(sourceType) {
8170
+ if isBasicFixedWideIntegerType(targetType) {
8171
+ if bits, ok := unsignedIntegerBits(targetType); ok {
8172
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
8173
+ "(" + value + ", " + strconv.Itoa(bits) + ")"
8174
+ }
8175
+ if _, ok := signedIntegerBits(targetType); ok {
8176
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperInt) + "(" + value + ")"
8177
+ }
8178
+ }
6737
8179
  if bits, ok := unsignedIntegerBits(targetType); ok && bits < 64 {
6738
8180
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
6739
8181
  "(" + value + ", " + strconv.Itoa(bits) + ")"
@@ -6751,12 +8193,28 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
6751
8193
  return value
6752
8194
  }
6753
8195
 
8196
+ func isBasicFixedWideIntegerType(typ types.Type) bool {
8197
+ basic, ok := types.Unalias(typ).(*types.Basic)
8198
+ if !ok {
8199
+ return false
8200
+ }
8201
+ switch basic.Kind() {
8202
+ case types.Int64, types.Uint64, types.Uintptr:
8203
+ return true
8204
+ default:
8205
+ return false
8206
+ }
8207
+ }
8208
+
6754
8209
  func (o *LoweringOwner) lowerNamedValueInterfaceWrapper(
6755
8210
  ctx lowerFileContext,
6756
8211
  targetType types.Type,
6757
8212
  sourceType types.Type,
6758
8213
  value string,
6759
8214
  ) string {
8215
+ if targetType == nil || sourceType == nil {
8216
+ return ""
8217
+ }
6760
8218
  if !isInterfaceType(targetType) || isInterfaceType(sourceType) {
6761
8219
  return ""
6762
8220
  }
@@ -6794,8 +8252,9 @@ func (o *LoweringOwner) lowerPrimitiveErrorWrapper(ctx lowerFileContext, sourceT
6794
8252
  if fn == nil {
6795
8253
  return ""
6796
8254
  }
6797
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperWrapPrimitiveError) +
6798
- "(" + value + ", " + o.methodFunctionExpr(ctx, named, fn, "Error") + ")"
8255
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
8256
+ "<$.GoError>(" + value + ", " + strconv.Quote(goRuntimeTypeString(sourceType)) +
8257
+ ", {\"Error\": " + o.methodFunctionExpr(ctx, named, fn, "Error") + "})"
6799
8258
  }
6800
8259
 
6801
8260
  func (o *LoweringOwner) lowerStructClone(value string) string {
@@ -6812,6 +8271,9 @@ func (o *LoweringOwner) lowerZeroValueExpr(typ types.Type) string {
6812
8271
 
6813
8272
  func (o *LoweringOwner) lowerZeroValueExprFor(ctx lowerFileContext, typ types.Type) string {
6814
8273
  if named := namedStructType(typ); named != nil && isStructValueType(typ) {
8274
+ if crossPackageUnexportedNamedType(ctx, named) {
8275
+ return "undefined as any"
8276
+ }
6815
8277
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue) + "(new " + o.namedTypeExpr(ctx, named) + "())"
6816
8278
  }
6817
8279
  switch typed := types.Unalias(typ).Underlying().(type) {
@@ -6859,7 +8321,7 @@ func (o *LoweringOwner) lowerDeclarationZeroValueExpr(ctx lowerFileContext, typ
6859
8321
  }
6860
8322
  return value
6861
8323
  }
6862
- if !signatureHasTypeParam(ctx.signature, typeParam) {
8324
+ if !typeParamInScope(ctx, typeParam) {
6863
8325
  return zeroValueExpr(typ)
6864
8326
  }
6865
8327
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperGenericZero) +
@@ -6870,6 +8332,15 @@ func (o *LoweringOwner) runtimeTypeInfoExpr(typ types.Type) string {
6870
8332
  return o.runtimeTypeInfoExprWithSeen(typ, make(map[types.Type]bool))
6871
8333
  }
6872
8334
 
8335
+ func (o *LoweringOwner) runtimeTypeAssertInfoExpr(ctx lowerFileContext, typ types.Type) string {
8336
+ typeParam, ok := types.Unalias(typ).(*types.TypeParam)
8337
+ if !ok || !typeParamInScope(ctx, typeParam) {
8338
+ return o.runtimeTypeInfoExpr(typ)
8339
+ }
8340
+ return "__typeArgs?.[" + strconv.Quote(typeParam.Obj().Name()) + "]?.type ?? " +
8341
+ o.runtimeTypeInfoExpr(typ)
8342
+ }
8343
+
6873
8344
  func (o *LoweringOwner) runtimeTypeInfoExprWithSeen(typ types.Type, seen map[types.Type]bool) string {
6874
8345
  typeKind := o.runtimeOwner.QualifiedHelper(RuntimeHelperTypeKind)
6875
8346
  if typ == nil {
@@ -6890,20 +8361,14 @@ func (o *LoweringOwner) runtimeTypeInfoExprWithSeen(typ types.Type, seen map[typ
6890
8361
  return o.runtimeFunctionTypeInfoWithSeen(named.Underlying().(*types.Signature), runtimeNamedTypeName(named), seen)
6891
8362
  }
6892
8363
  if named := namedNonStructType(typ); named != nil {
8364
+ if basic, ok := types.Unalias(named.Underlying()).(*types.Basic); ok {
8365
+ return runtimeBasicTypeInfoExpr(typeKind, basic, runtimeNamedTypeName(named))
8366
+ }
6893
8367
  return strconv.Quote(runtimeNamedTypeName(named))
6894
8368
  }
6895
8369
  switch typed := types.Unalias(typ).Underlying().(type) {
6896
8370
  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
- }
8371
+ return runtimeBasicTypeInfoExpr(typeKind, typed, "")
6907
8372
  case *types.Pointer:
6908
8373
  return "{ kind: " + typeKind + ".Pointer, elemType: " + o.runtimeTypeInfoExprWithSeen(typed.Elem(), seen) + " }"
6909
8374
  case *types.Struct:
@@ -6926,6 +8391,23 @@ func (o *LoweringOwner) runtimeTypeInfoExprWithSeen(typ types.Type, seen map[typ
6926
8391
  }
6927
8392
  }
6928
8393
 
8394
+ func runtimeBasicTypeInfoExpr(typeKind string, basic *types.Basic, typeName string) string {
8395
+ name := "unknown"
8396
+ switch {
8397
+ case basic.Info()&types.IsBoolean != 0:
8398
+ name = "bool"
8399
+ case basic.Info()&types.IsString != 0:
8400
+ name = "string"
8401
+ case basic.Info()&types.IsNumeric != 0:
8402
+ name = basicRuntimeName(basic)
8403
+ }
8404
+ parts := []string{"kind: " + typeKind + ".Basic", "name: " + strconv.Quote(name)}
8405
+ if typeName != "" {
8406
+ parts = append(parts, "typeName: "+strconv.Quote(typeName))
8407
+ }
8408
+ return "{ " + strings.Join(parts, ", ") + " }"
8409
+ }
8410
+
6929
8411
  func (o *LoweringOwner) shallowRuntimeTypeInfoExpr(typ types.Type) string {
6930
8412
  typeKind := o.runtimeOwner.QualifiedHelper(RuntimeHelperTypeKind)
6931
8413
  switch types.Unalias(typ).Underlying().(type) {
@@ -6998,7 +8480,8 @@ func (o *LoweringOwner) runtimeFunctionTypeInfoWithSeen(signature *types.Signatu
6998
8480
  if signature.Variadic() {
6999
8481
  parts = append(parts, "isVariadic: true")
7000
8482
  }
7001
- return "{ " + strings.Join(parts, ", ") + " }"
8483
+ runtimePackage := strings.TrimSuffix(typeKind, ".TypeKind")
8484
+ return "({ " + strings.Join(parts, ", ") + " } as " + runtimePackage + ".FunctionTypeInfo)"
7002
8485
  }
7003
8486
 
7004
8487
  func (o *LoweringOwner) runtimeSignatureTypes(tuple *types.Tuple, seen map[types.Type]bool) string {
@@ -7012,20 +8495,11 @@ func (o *LoweringOwner) runtimeSignatureTypes(tuple *types.Tuple, seen map[types
7012
8495
  return "[" + strings.Join(types, ", ") + "]"
7013
8496
  }
7014
8497
 
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
8498
  func tsStructFieldName(name string, idx int) string {
7025
8499
  if name == "_" {
7026
8500
  return "_blank" + strconv.Itoa(idx)
7027
8501
  }
7028
- return name
8502
+ return safeIdentifier(name)
7029
8503
  }
7030
8504
 
7031
8505
  func shouldCloneStructValue(expr ast.Expr) bool {
@@ -7076,6 +8550,11 @@ func (o *LoweringOwner) tsSignatureResultFor(ctx lowerFileContext, signature *ty
7076
8550
  }
7077
8551
 
7078
8552
  func (o *LoweringOwner) tsSignatureResultTypeFor(ctx lowerFileContext, typ types.Type) string {
8553
+ if named, ok := types.Unalias(typ).(*types.Named); ok {
8554
+ if _, ok := types.Unalias(named.Underlying()).(*types.Signature); ok {
8555
+ return o.tsTypeFor(ctx, typ)
8556
+ }
8557
+ }
7079
8558
  if signature := signatureForType(typ); ctx.functionTypeDepth == 0 && signature != nil {
7080
8559
  return o.tsAsyncCompatibleFunctionResultTypeFor(ctx, signature)
7081
8560
  }
@@ -7139,6 +8618,13 @@ func asyncCompatibleResultType(result string) string {
7139
8618
  return result + " | " + tsPromiseType(result)
7140
8619
  }
7141
8620
 
8621
+ func asyncCompatibleMethodResultType(result string, async bool) string {
8622
+ if !async {
8623
+ return result
8624
+ }
8625
+ return asyncCompatibleResultType(result)
8626
+ }
8627
+
7142
8628
  func tsPromiseType(result string) string {
7143
8629
  return "globalThis.Promise<" + result + ">"
7144
8630
  }
@@ -7203,10 +8689,16 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
7203
8689
  if crossPackageUnexportedNamedType(ctx, named) {
7204
8690
  return "any"
7205
8691
  }
8692
+ if !ctx.canReferenceNamedType(named) {
8693
+ return "any"
8694
+ }
7206
8695
  name := o.namedTypeExpr(ctx, named)
7207
8696
  if _, ok := named.Underlying().(*types.Interface); ok {
7208
8697
  return name + " | null"
7209
8698
  }
8699
+ if _, ok := types.Unalias(named.Underlying()).(*types.Signature); ok {
8700
+ return name + " | null"
8701
+ }
7210
8702
  return name
7211
8703
  }
7212
8704
  switch typed := types.Unalias(typ).Underlying().(type) {
@@ -7233,7 +8725,7 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
7233
8725
  }
7234
8726
  return tsArrayType(o.tsTypeFor(ctx, typed.Elem()))
7235
8727
  case *types.Slice:
7236
- return "$.Slice<" + o.tsTypeFor(ctx, typed.Elem()) + ">"
8728
+ return "$.Slice<" + o.tsSliceElemTypeFor(ctx, typed.Elem()) + ">"
7237
8729
  case *types.Map:
7238
8730
  return "Map<" + o.tsTypeFor(ctx, typed.Key()) + ", " + o.tsTypeFor(ctx, typed.Elem()) + "> | null"
7239
8731
  case *types.Chan:
@@ -7251,12 +8743,18 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
7251
8743
  if crossPackageUnexportedNamedType(ctx, named) {
7252
8744
  return "any"
7253
8745
  }
8746
+ if !ctx.canReferenceNamedType(named) {
8747
+ return "any"
8748
+ }
7254
8749
  return "$.VarRef<" + o.namedTypeExpr(ctx, named) + "> | null"
7255
8750
  }
7256
8751
  if named := namedStructType(typed.Elem()); named != nil {
7257
8752
  if crossPackageUnexportedNamedType(ctx, named) {
7258
8753
  return "any"
7259
8754
  }
8755
+ if !ctx.canReferenceNamedType(named) {
8756
+ return "any"
8757
+ }
7260
8758
  name := o.namedTypeExpr(ctx, named)
7261
8759
  return name + " | $.VarRef<" + name + "> | null"
7262
8760
  }
@@ -7272,6 +8770,19 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
7272
8770
  }
7273
8771
  }
7274
8772
 
8773
+ func (o *LoweringOwner) tsSliceElemTypeFor(ctx lowerFileContext, typ types.Type) string {
8774
+ if typeParam, ok := types.Unalias(typ).(*types.TypeParam); ok && staticTypeParamInScope(ctx, typeParam) {
8775
+ return safeIdentifier(typeParam.Obj().Name())
8776
+ }
8777
+ if pointer, ok := types.Unalias(typ).(*types.Pointer); ok {
8778
+ if typeParam, ok := types.Unalias(pointer.Elem()).(*types.TypeParam); ok && staticTypeParamInScope(ctx, typeParam) {
8779
+ name := safeIdentifier(typeParam.Obj().Name())
8780
+ return name + " | $.VarRef<" + name + "> | null"
8781
+ }
8782
+ }
8783
+ return o.tsTypeFor(ctx, typ)
8784
+ }
8785
+
7275
8786
  func (o *LoweringOwner) tsNonNilTypeFor(ctx lowerFileContext, typ types.Type) string {
7276
8787
  if isBuiltinErrorType(typ) {
7277
8788
  return "Exclude<$.GoError, null>"
@@ -7288,6 +8799,9 @@ func (o *LoweringOwner) aliasTypeExpr(ctx lowerFileContext, alias *types.Alias)
7288
8799
  if alias == nil || alias.Obj() == nil {
7289
8800
  return "unknown"
7290
8801
  }
8802
+ if !ctx.canReferenceObjectPackage(alias.Obj()) {
8803
+ return "any"
8804
+ }
7291
8805
  if alias.Obj().Pkg() == nil {
7292
8806
  return o.tsTypeFor(ctx, alias.Rhs())
7293
8807
  }
@@ -7397,6 +8911,14 @@ func namedStructType(typ types.Type) *types.Named {
7397
8911
  return named
7398
8912
  }
7399
8913
 
8914
+ func pointerToNamedStructType(typ types.Type) *types.Named {
8915
+ pointer, ok := types.Unalias(typ).Underlying().(*types.Pointer)
8916
+ if !ok {
8917
+ return nil
8918
+ }
8919
+ return namedStructType(pointer.Elem())
8920
+ }
8921
+
7400
8922
  func namedNonStructType(typ types.Type) *types.Named {
7401
8923
  named, _ := types.Unalias(typ).(*types.Named)
7402
8924
  if named == nil {
@@ -7458,6 +8980,94 @@ func signatureHasTypeParam(signature *types.Signature, target *types.TypeParam)
7458
8980
  return false
7459
8981
  }
7460
8982
 
8983
+ func typeParamInScope(ctx lowerFileContext, target *types.TypeParam) bool {
8984
+ if target == nil {
8985
+ return false
8986
+ }
8987
+ if signatureHasTypeParam(ctx.signature, target) {
8988
+ return true
8989
+ }
8990
+ return ctx.typeParams[target.Obj().Name()]
8991
+ }
8992
+
8993
+ func staticTypeParamInScope(ctx lowerFileContext, target *types.TypeParam) bool {
8994
+ if target == nil || !typeParamInScope(ctx, target) {
8995
+ return false
8996
+ }
8997
+ return ctx.staticTypeParams[target.Obj().Name()]
8998
+ }
8999
+
9000
+ func typeParamConstraintIsAny(typeParam *types.TypeParam) bool {
9001
+ if typeParam == nil {
9002
+ return false
9003
+ }
9004
+ iface, ok := typeParam.Constraint().Underlying().(*types.Interface)
9005
+ if !ok {
9006
+ return false
9007
+ }
9008
+ return iface.NumMethods() == 0 && iface.NumEmbeddeds() == 0
9009
+ }
9010
+
9011
+ func signatureTypeParamNames(signature *types.Signature) []string {
9012
+ if signature == nil || signature.TypeParams() == nil {
9013
+ return nil
9014
+ }
9015
+ typeParams := signature.TypeParams()
9016
+ names := make([]string, 0, typeParams.Len())
9017
+ for typeParam := range typeParams.TypeParams() {
9018
+ if !signatureUsesTypeParamAsSliceElem(signature, typeParam) {
9019
+ continue
9020
+ }
9021
+ names = append(names, safeIdentifier(typeParam.Obj().Name()))
9022
+ }
9023
+ return names
9024
+ }
9025
+
9026
+ func signatureUsesTypeParamAsSliceElem(signature *types.Signature, target *types.TypeParam) bool {
9027
+ if signature == nil || target == nil {
9028
+ return false
9029
+ }
9030
+ return tupleUsesTypeParamAsSliceElem(signature.Params(), target) ||
9031
+ tupleUsesTypeParamAsSliceElem(signature.Results(), target)
9032
+ }
9033
+
9034
+ func tupleUsesTypeParamAsSliceElem(tuple *types.Tuple, target *types.TypeParam) bool {
9035
+ if tuple == nil {
9036
+ return false
9037
+ }
9038
+ for variable := range tuple.Variables() {
9039
+ if typeUsesTypeParamAsSliceElem(variable.Type(), target) {
9040
+ return true
9041
+ }
9042
+ }
9043
+ return false
9044
+ }
9045
+
9046
+ func typeUsesTypeParamAsSliceElem(typ types.Type, target *types.TypeParam) bool {
9047
+ switch typed := types.Unalias(typ).Underlying().(type) {
9048
+ case *types.Slice:
9049
+ if typeParam, ok := types.Unalias(typed.Elem()).(*types.TypeParam); ok &&
9050
+ (typeParam == target || typeParam.Obj() == target.Obj()) {
9051
+ return true
9052
+ }
9053
+ return typeUsesTypeParamAsSliceElem(typed.Elem(), target)
9054
+ case *types.Array:
9055
+ return typeUsesTypeParamAsSliceElem(typed.Elem(), target)
9056
+ case *types.Pointer:
9057
+ return typeUsesTypeParamAsSliceElem(typed.Elem(), target)
9058
+ case *types.Map:
9059
+ return typeUsesTypeParamAsSliceElem(typed.Key(), target) ||
9060
+ typeUsesTypeParamAsSliceElem(typed.Elem(), target)
9061
+ case *types.Chan:
9062
+ return typeUsesTypeParamAsSliceElem(typed.Elem(), target)
9063
+ case *types.Signature:
9064
+ return tupleUsesTypeParamAsSliceElem(typed.Params(), target) ||
9065
+ tupleUsesTypeParamAsSliceElem(typed.Results(), target)
9066
+ default:
9067
+ return false
9068
+ }
9069
+ }
9070
+
7461
9071
  func sameNamedTypeOrigin(a *types.Named, b *types.Named) bool {
7462
9072
  if a == nil || b == nil {
7463
9073
  return false
@@ -7585,6 +9195,11 @@ func isIntegerType(typ types.Type) bool {
7585
9195
  return ok && basic.Info()&types.IsInteger != 0
7586
9196
  }
7587
9197
 
9198
+ func isFloatType(typ types.Type) bool {
9199
+ basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
9200
+ return ok && basic.Info()&types.IsFloat != 0
9201
+ }
9202
+
7588
9203
  func unsignedIntegerBits(typ types.Type) (int, bool) {
7589
9204
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
7590
9205
  if !ok || basic.Info()&types.IsUnsigned == 0 {
@@ -7632,6 +9247,9 @@ func isWideIntegerType(typ types.Type) bool {
7632
9247
  }
7633
9248
 
7634
9249
  func isFixedWideIntegerType(typ types.Type) bool {
9250
+ if typ == nil {
9251
+ return false
9252
+ }
7635
9253
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
7636
9254
  if !ok {
7637
9255
  return false
@@ -7644,6 +9262,14 @@ func isFixedWideIntegerType(typ types.Type) bool {
7644
9262
  }
7645
9263
  }
7646
9264
 
9265
+ func isFixedSignedWideIntegerType(typ types.Type) bool {
9266
+ if typ == nil {
9267
+ return false
9268
+ }
9269
+ basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
9270
+ return ok && basic.Kind() == types.Int64
9271
+ }
9272
+
7647
9273
  func isRuneSliceType(typ types.Type) bool {
7648
9274
  slice, ok := types.Unalias(typ).Underlying().(*types.Slice)
7649
9275
  return ok && isRuneType(slice.Elem())
@@ -7672,6 +9298,8 @@ func sliceTypeHint(typ types.Type) string {
7672
9298
  return "string"
7673
9299
  case isNumericType(typ):
7674
9300
  return "number"
9301
+ case isBoolType(typ):
9302
+ return "boolean"
7675
9303
  default:
7676
9304
  return ""
7677
9305
  }
@@ -7800,6 +9428,13 @@ func (o *LoweringOwner) awaitCallIfNeeded(ctx lowerFileContext, fun ast.Expr, ca
7800
9428
  return call
7801
9429
  }
7802
9430
 
9431
+ func parenthesizeAwaitedExpr(expr string) string {
9432
+ if strings.HasPrefix(expr, "await ") {
9433
+ return "(" + expr + ")"
9434
+ }
9435
+ return expr
9436
+ }
9437
+
7803
9438
  func (o *LoweringOwner) genericTypeArgsExpr(ctx lowerFileContext, callee ast.Expr, typeArgExprs []ast.Expr) string {
7804
9439
  signature := genericFunctionSignature(ctx, callee)
7805
9440
  if signature == nil {
@@ -7883,7 +9518,7 @@ func (o *LoweringOwner) inferGenericTypeArg(
7883
9518
  }
7884
9519
 
7885
9520
  func (o *LoweringOwner) genericTypeDescriptorExpr(ctx lowerFileContext, typ types.Type) string {
7886
- if typeParam, ok := types.Unalias(typ).(*types.TypeParam); ok && signatureHasTypeParam(ctx.signature, typeParam) {
9521
+ if typeParam, ok := types.Unalias(typ).(*types.TypeParam); ok && typeParamInScope(ctx, typeParam) {
7887
9522
  return "__typeArgs?.[" + strconv.Quote(typeParam.Obj().Name()) + "] ?? { type: " +
7888
9523
  o.runtimeTypeInfoExpr(typ) + ", zero: () => " + o.lowerZeroValueExprFor(ctx, typ) + " }"
7889
9524
  }
@@ -7921,7 +9556,16 @@ func (o *LoweringOwner) genericMethodDescriptorsForType(
7921
9556
  methods = append(methods, method.Name()+": (receiver: any, ...args: any[]) => receiver."+method.Name()+"(...args)")
7922
9557
  continue
7923
9558
  }
7924
- methods = append(methods, method.Name()+": "+o.methodFunctionExpr(ctx, named.Origin(), method, method.Name()))
9559
+ receiver := "receiver"
9560
+ if sig, _ := method.Type().(*types.Signature); sig != nil {
9561
+ if recv := sig.Recv(); recv != nil {
9562
+ if _, ok := types.Unalias(recv.Type()).Underlying().(*types.Pointer); !ok {
9563
+ receiver = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + "(receiver)"
9564
+ }
9565
+ }
9566
+ }
9567
+ methods = append(methods, method.Name()+": (receiver: any, ...args: any[]) => "+
9568
+ "("+o.methodFunctionExpr(ctx, named.Origin(), method, method.Name())+" as any)("+receiver+", ...args)")
7925
9569
  }
7926
9570
  if len(methods) == 0 {
7927
9571
  return ""
@@ -7951,6 +9595,18 @@ func methodFunctionName(receiver *types.Named, method string) string {
7951
9595
  return receiver.Obj().Name() + "_" + method
7952
9596
  }
7953
9597
 
9598
+ func methodReceiverNamedType(obj types.Object) *types.Named {
9599
+ fn, _ := obj.(*types.Func)
9600
+ if fn == nil {
9601
+ return nil
9602
+ }
9603
+ signature, _ := fn.Type().(*types.Signature)
9604
+ if signature == nil || signature.Recv() == nil {
9605
+ return nil
9606
+ }
9607
+ return receiverNamedType(signature.Recv().Type())
9608
+ }
9609
+
7954
9610
  func (o *LoweringOwner) methodFunctionExpr(
7955
9611
  ctx lowerFileContext,
7956
9612
  receiver *types.Named,