goscript 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/README.md +5 -2
  2. package/cmd/go_js_wasm_exec/main.go +201 -0
  3. package/cmd/go_js_wasm_exec/main_test.go +83 -0
  4. package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +35 -8
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/cmd/goscript/cmd_compile_test.go +105 -6
  8. package/compiler/build-flags.go +9 -10
  9. package/compiler/compile-request.go +12 -9
  10. package/compiler/compliance_test.go +0 -1
  11. package/compiler/config.go +2 -0
  12. package/compiler/gotest/request.go +28 -0
  13. package/compiler/gotest/runner.go +353 -27
  14. package/compiler/gotest/runner_test.go +400 -1
  15. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  16. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  17. package/compiler/lowered-program.go +24 -17
  18. package/compiler/lowering.go +988 -263
  19. package/compiler/lowering_bench_test.go +364 -0
  20. package/compiler/override-facts.go +15 -0
  21. package/compiler/override-parity-verifier.go +450 -0
  22. package/compiler/override-parity.go +122 -0
  23. package/compiler/override-registry_test.go +559 -0
  24. package/compiler/package-graph.go +61 -4
  25. package/compiler/package-graph_test.go +30 -0
  26. package/compiler/protobuf-ts-binding.go +514 -0
  27. package/compiler/protobuf-ts-binding_test.go +172 -0
  28. package/compiler/semantic-model-types.go +17 -4
  29. package/compiler/semantic-model.go +709 -72
  30. package/compiler/semantic-model_test.go +219 -0
  31. package/compiler/service.go +20 -1
  32. package/compiler/skeleton_test.go +1008 -20
  33. package/compiler/typescript-emitter.go +147 -15
  34. package/dist/gs/builtin/builtin.d.ts +2 -2
  35. package/dist/gs/builtin/builtin.js +20 -0
  36. package/dist/gs/builtin/builtin.js.map +1 -1
  37. package/dist/gs/builtin/slice.d.ts +2 -1
  38. package/dist/gs/builtin/slice.js +34 -4
  39. package/dist/gs/builtin/slice.js.map +1 -1
  40. package/dist/gs/builtin/type.d.ts +14 -6
  41. package/dist/gs/builtin/type.js +224 -64
  42. package/dist/gs/builtin/type.js.map +1 -1
  43. package/dist/gs/builtin/varRef.d.ts +11 -0
  44. package/dist/gs/builtin/varRef.js +57 -2
  45. package/dist/gs/builtin/varRef.js.map +1 -1
  46. package/dist/gs/bytes/buffer.gs.js +1 -1
  47. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  48. package/dist/gs/bytes/reader.gs.js +1 -1
  49. package/dist/gs/bytes/reader.gs.js.map +1 -1
  50. package/dist/gs/compress/zlib/index.d.ts +13 -6
  51. package/dist/gs/compress/zlib/index.js +131 -35
  52. package/dist/gs/compress/zlib/index.js.map +1 -1
  53. package/dist/gs/crypto/sha1/index.js +2 -5
  54. package/dist/gs/crypto/sha1/index.js.map +1 -1
  55. package/dist/gs/crypto/sha256/index.js +2 -5
  56. package/dist/gs/crypto/sha256/index.js.map +1 -1
  57. package/dist/gs/crypto/sha512/index.js +2 -5
  58. package/dist/gs/crypto/sha512/index.js.map +1 -1
  59. package/dist/gs/embed/index.d.ts +6 -0
  60. package/dist/gs/embed/index.js +210 -5
  61. package/dist/gs/embed/index.js.map +1 -1
  62. package/dist/gs/encoding/json/index.d.ts +114 -0
  63. package/dist/gs/encoding/json/index.js +544 -36
  64. package/dist/gs/encoding/json/index.js.map +1 -1
  65. package/dist/gs/fmt/fmt.d.ts +3 -3
  66. package/dist/gs/fmt/fmt.js +29 -16
  67. package/dist/gs/fmt/fmt.js.map +1 -1
  68. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
  69. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
  70. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  71. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  72. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  73. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  74. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  75. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  76. package/dist/gs/go/scanner/index.d.ts +2 -0
  77. package/dist/gs/go/scanner/index.js +29 -5
  78. package/dist/gs/go/scanner/index.js.map +1 -1
  79. package/dist/gs/go/token/index.js +22 -6
  80. package/dist/gs/go/token/index.js.map +1 -1
  81. package/dist/gs/hash/index.d.ts +6 -0
  82. package/dist/gs/hash/index.js +20 -0
  83. package/dist/gs/hash/index.js.map +1 -1
  84. package/dist/gs/internal/goarch/index.d.ts +43 -3
  85. package/dist/gs/internal/goarch/index.js +42 -10
  86. package/dist/gs/internal/goarch/index.js.map +1 -1
  87. package/dist/gs/io/fs/fs.js +26 -14
  88. package/dist/gs/io/fs/fs.js.map +1 -1
  89. package/dist/gs/io/fs/readdir.js +8 -4
  90. package/dist/gs/io/fs/readdir.js.map +1 -1
  91. package/dist/gs/io/fs/sub.js +8 -1
  92. package/dist/gs/io/fs/sub.js.map +1 -1
  93. package/dist/gs/io/io.d.ts +12 -6
  94. package/dist/gs/io/io.js +87 -42
  95. package/dist/gs/io/io.js.map +1 -1
  96. package/dist/gs/math/bits/index.d.ts +31 -5
  97. package/dist/gs/math/bits/index.js +29 -28
  98. package/dist/gs/math/bits/index.js.map +1 -1
  99. package/dist/gs/mime/index.d.ts +16 -0
  100. package/dist/gs/mime/index.js +315 -6
  101. package/dist/gs/mime/index.js.map +1 -1
  102. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  103. package/dist/gs/net/http/httptest/index.js +85 -6
  104. package/dist/gs/net/http/httptest/index.js.map +1 -1
  105. package/dist/gs/net/http/index.d.ts +303 -6
  106. package/dist/gs/net/http/index.js +1615 -58
  107. package/dist/gs/net/http/index.js.map +1 -1
  108. package/dist/gs/os/dir_unix.gs.js +1 -1
  109. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  110. package/dist/gs/os/error.gs.js +1 -1
  111. package/dist/gs/os/error.gs.js.map +1 -1
  112. package/dist/gs/os/exec.gs.d.ts +1 -0
  113. package/dist/gs/os/exec.gs.js +4 -8
  114. package/dist/gs/os/exec.gs.js.map +1 -1
  115. package/dist/gs/os/exec_posix.gs.js +1 -1
  116. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  117. package/dist/gs/os/index.d.ts +1 -1
  118. package/dist/gs/os/index.js +1 -1
  119. package/dist/gs/os/index.js.map +1 -1
  120. package/dist/gs/os/proc.gs.d.ts +4 -0
  121. package/dist/gs/os/proc.gs.js +12 -6
  122. package/dist/gs/os/proc.gs.js.map +1 -1
  123. package/dist/gs/os/root_js.gs.js +1 -1
  124. package/dist/gs/os/root_js.gs.js.map +1 -1
  125. package/dist/gs/os/types.gs.js +1 -1
  126. package/dist/gs/os/types.gs.js.map +1 -1
  127. package/dist/gs/os/types_js.gs.d.ts +6 -2
  128. package/dist/gs/os/types_js.gs.js +170 -9
  129. package/dist/gs/os/types_js.gs.js.map +1 -1
  130. package/dist/gs/os/types_unix.gs.js +1 -1
  131. package/dist/gs/os/types_unix.gs.js.map +1 -1
  132. package/dist/gs/path/path.js +11 -7
  133. package/dist/gs/path/path.js.map +1 -1
  134. package/dist/gs/reflect/index.d.ts +5 -4
  135. package/dist/gs/reflect/index.js +4 -3
  136. package/dist/gs/reflect/index.js.map +1 -1
  137. package/dist/gs/reflect/map.js +15 -0
  138. package/dist/gs/reflect/map.js.map +1 -1
  139. package/dist/gs/reflect/type.d.ts +26 -6
  140. package/dist/gs/reflect/type.js +1498 -279
  141. package/dist/gs/reflect/type.js.map +1 -1
  142. package/dist/gs/reflect/types.d.ts +14 -6
  143. package/dist/gs/reflect/types.js +35 -1
  144. package/dist/gs/reflect/types.js.map +1 -1
  145. package/dist/gs/reflect/value.d.ts +1 -0
  146. package/dist/gs/reflect/value.js +83 -41
  147. package/dist/gs/reflect/value.js.map +1 -1
  148. package/dist/gs/reflect/visiblefields.js +4 -140
  149. package/dist/gs/reflect/visiblefields.js.map +1 -1
  150. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  151. package/dist/gs/runtime/pprof/index.js +50 -30
  152. package/dist/gs/runtime/pprof/index.js.map +1 -1
  153. package/dist/gs/runtime/runtime.js +5 -4
  154. package/dist/gs/runtime/runtime.js.map +1 -1
  155. package/dist/gs/runtime/trace/index.js +5 -19
  156. package/dist/gs/runtime/trace/index.js.map +1 -1
  157. package/dist/gs/strconv/atoi.gs.js +1 -1
  158. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  159. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  160. package/dist/gs/strconv/complex.gs.js +148 -0
  161. package/dist/gs/strconv/complex.gs.js.map +1 -0
  162. package/dist/gs/strconv/index.d.ts +1 -0
  163. package/dist/gs/strconv/index.js +1 -0
  164. package/dist/gs/strconv/index.js.map +1 -1
  165. package/dist/gs/strings/builder.js +1 -1
  166. package/dist/gs/strings/reader.d.ts +1 -1
  167. package/dist/gs/strings/reader.js +11 -7
  168. package/dist/gs/strings/reader.js.map +1 -1
  169. package/dist/gs/strings/replace.js +15 -7
  170. package/dist/gs/strings/replace.js.map +1 -1
  171. package/dist/gs/strings/strings.d.ts +5 -0
  172. package/dist/gs/strings/strings.js +57 -5
  173. package/dist/gs/strings/strings.js.map +1 -1
  174. package/dist/gs/sync/atomic/type.gs.js +9 -9
  175. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  176. package/dist/gs/sync/atomic/value.gs.js +2 -2
  177. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  178. package/dist/gs/sync/sync.d.ts +2 -1
  179. package/dist/gs/sync/sync.js +37 -16
  180. package/dist/gs/sync/sync.js.map +1 -1
  181. package/dist/gs/syscall/env.js +22 -14
  182. package/dist/gs/syscall/env.js.map +1 -1
  183. package/dist/gs/syscall/js/index.js +9 -0
  184. package/dist/gs/syscall/js/index.js.map +1 -1
  185. package/dist/gs/testing/testing.js +59 -15
  186. package/dist/gs/testing/testing.js.map +1 -1
  187. package/dist/gs/time/time.d.ts +24 -1
  188. package/dist/gs/time/time.js +43 -3
  189. package/dist/gs/time/time.js.map +1 -1
  190. package/dist/gs/unique/index.js +7 -1
  191. package/dist/gs/unique/index.js.map +1 -1
  192. package/go.mod +3 -3
  193. package/go.sum +16 -0
  194. package/gs/builtin/builtin.ts +25 -2
  195. package/gs/builtin/runtime-contract.test.ts +260 -18
  196. package/gs/builtin/slice.ts +51 -4
  197. package/gs/builtin/type.ts +310 -63
  198. package/gs/builtin/varRef.ts +85 -2
  199. package/gs/bytes/buffer.gs.ts +1 -1
  200. package/gs/bytes/reader.gs.ts +1 -1
  201. package/gs/compress/zlib/index.test.ts +159 -1
  202. package/gs/compress/zlib/index.ts +164 -37
  203. package/gs/compress/zlib/meta.json +4 -1
  204. package/gs/compress/zlib/parity.json +51 -0
  205. package/gs/crypto/sha1/index.test.ts +19 -2
  206. package/gs/crypto/sha1/index.ts +3 -6
  207. package/gs/crypto/sha256/index.test.ts +14 -2
  208. package/gs/crypto/sha256/index.ts +3 -6
  209. package/gs/crypto/sha512/index.test.ts +17 -2
  210. package/gs/crypto/sha512/index.ts +3 -6
  211. package/gs/embed/index.test.ts +87 -0
  212. package/gs/embed/index.ts +229 -5
  213. package/gs/encoding/json/index.test.ts +360 -6
  214. package/gs/encoding/json/index.ts +679 -38
  215. package/gs/encoding/json/parity.json +81 -0
  216. package/gs/fmt/fmt.test.ts +41 -3
  217. package/gs/fmt/fmt.ts +40 -17
  218. package/gs/fmt/meta.json +6 -1
  219. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
  220. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
  221. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  222. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  223. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  224. package/gs/github.com/pkg/errors/errors.ts +54 -30
  225. package/gs/go/scanner/index.test.ts +39 -56
  226. package/gs/go/scanner/index.ts +33 -5
  227. package/gs/go/scanner/parity.json +27 -0
  228. package/gs/go/token/index.ts +22 -6
  229. package/gs/hash/index.test.ts +20 -33
  230. package/gs/hash/index.ts +28 -0
  231. package/gs/hash/parity.json +21 -0
  232. package/gs/internal/goarch/index.test.ts +32 -0
  233. package/gs/internal/goarch/index.ts +45 -13
  234. package/gs/internal/goarch/parity.json +144 -0
  235. package/gs/io/fs/fs.ts +26 -14
  236. package/gs/io/fs/readdir.test.ts +38 -0
  237. package/gs/io/fs/readdir.ts +8 -4
  238. package/gs/io/fs/sub.ts +8 -1
  239. package/gs/io/io.test.ts +77 -6
  240. package/gs/io/io.ts +115 -52
  241. package/gs/io/meta.json +7 -1
  242. package/gs/io/parity.json +162 -0
  243. package/gs/math/bits/index.test.ts +14 -1
  244. package/gs/math/bits/index.ts +75 -32
  245. package/gs/math/bits/parity.json +156 -0
  246. package/gs/mime/index.test.ts +90 -0
  247. package/gs/mime/index.ts +369 -6
  248. package/gs/mime/parity.json +36 -0
  249. package/gs/net/http/httptest/index.test.ts +98 -2
  250. package/gs/net/http/httptest/index.ts +101 -6
  251. package/gs/net/http/httptest/parity.json +15 -0
  252. package/gs/net/http/index.test.ts +797 -12
  253. package/gs/net/http/index.ts +1874 -136
  254. package/gs/net/http/meta.json +16 -1
  255. package/gs/net/http/parity.json +193 -0
  256. package/gs/os/dir_unix.gs.ts +1 -1
  257. package/gs/os/error.gs.ts +1 -1
  258. package/gs/os/exec.gs.ts +4 -8
  259. package/gs/os/exec_posix.gs.ts +1 -1
  260. package/gs/os/file_unix_js.test.ts +52 -0
  261. package/gs/os/index.test.ts +9 -0
  262. package/gs/os/index.ts +1 -0
  263. package/gs/os/meta.json +4 -0
  264. package/gs/os/parity.json +9 -0
  265. package/gs/os/proc.gs.ts +18 -5
  266. package/gs/os/proc.test.ts +26 -0
  267. package/gs/os/readdir.test.ts +56 -0
  268. package/gs/os/root_js.gs.ts +1 -1
  269. package/gs/os/types.gs.ts +1 -1
  270. package/gs/os/types_js.gs.ts +170 -9
  271. package/gs/os/types_unix.gs.ts +1 -1
  272. package/gs/path/path.ts +11 -7
  273. package/gs/reflect/deepequal.test.ts +10 -1
  274. package/gs/reflect/field.test.ts +37 -15
  275. package/gs/reflect/function-types.test.ts +518 -22
  276. package/gs/reflect/index.ts +8 -6
  277. package/gs/reflect/map.ts +20 -0
  278. package/gs/reflect/meta.json +6 -4
  279. package/gs/reflect/parity.json +234 -0
  280. package/gs/reflect/sliceat.test.ts +156 -0
  281. package/gs/reflect/structof.test.ts +401 -0
  282. package/gs/reflect/type.ts +1980 -365
  283. package/gs/reflect/typefor.test.ts +540 -10
  284. package/gs/reflect/types.ts +43 -18
  285. package/gs/reflect/value.ts +105 -45
  286. package/gs/reflect/visiblefields.ts +5 -168
  287. package/gs/runtime/parity.json +24 -0
  288. package/gs/runtime/pprof/index.test.ts +29 -7
  289. package/gs/runtime/pprof/index.ts +56 -30
  290. package/gs/runtime/pprof/parity.json +27 -0
  291. package/gs/runtime/runtime.test.ts +3 -1
  292. package/gs/runtime/runtime.ts +4 -3
  293. package/gs/runtime/trace/index.test.ts +5 -3
  294. package/gs/runtime/trace/index.ts +8 -20
  295. package/gs/runtime/trace/parity.json +36 -0
  296. package/gs/strconv/atoi.gs.ts +1 -1
  297. package/gs/strconv/complex.gs.ts +174 -0
  298. package/gs/strconv/complex.test.ts +65 -0
  299. package/gs/strconv/index.ts +1 -0
  300. package/gs/strconv/parity.json +120 -0
  301. package/gs/strings/builder.ts +1 -1
  302. package/gs/strings/meta.json +5 -2
  303. package/gs/strings/parity.json +186 -0
  304. package/gs/strings/reader.test.ts +2 -2
  305. package/gs/strings/reader.ts +11 -7
  306. package/gs/strings/replace.ts +15 -7
  307. package/gs/strings/strings.test.ts +22 -2
  308. package/gs/strings/strings.ts +64 -6
  309. package/gs/sync/atomic/type.gs.ts +9 -9
  310. package/gs/sync/atomic/value.gs.ts +2 -2
  311. package/gs/sync/meta.json +1 -0
  312. package/gs/sync/sync.test.ts +41 -1
  313. package/gs/sync/sync.ts +41 -16
  314. package/gs/syscall/env.ts +29 -14
  315. package/gs/syscall/js/index.test.ts +18 -0
  316. package/gs/syscall/js/index.ts +12 -0
  317. package/gs/testing/testing.test.ts +99 -3
  318. package/gs/testing/testing.ts +95 -24
  319. package/gs/time/parity.json +225 -0
  320. package/gs/time/time.test.ts +20 -2
  321. package/gs/time/time.ts +49 -7
  322. package/gs/unique/index.ts +7 -1
  323. package/package.json +4 -2
  324. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  325. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -814
  326. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  327. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -31
  328. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1233
  329. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
  330. /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
@@ -24,6 +24,16 @@ type LoweringOwner struct {
24
24
  overrideOwner *OverrideRegistryOwner
25
25
  }
26
26
 
27
+ // LoweringOptions are request-scoped lowering switches.
28
+ type LoweringOptions struct {
29
+ // SourceRoot is the request source root that may contain sibling protobuf TypeScript files.
30
+ SourceRoot string
31
+ // OutputPath is the TypeScript output root used for generated relative imports.
32
+ OutputPath string
33
+ // ProtobufTypeScriptBinding binds .pb.go files to sibling .pb.ts files.
34
+ ProtobufTypeScriptBinding bool
35
+ }
36
+
27
37
  // NewLoweringOwner creates the lowering owner.
28
38
  func NewLoweringOwner(runtimeOwner *RuntimeContractOwner, overrideOwner *OverrideRegistryOwner) *LoweringOwner {
29
39
  if runtimeOwner == nil {
@@ -39,7 +49,7 @@ func NewLoweringOwner(runtimeOwner *RuntimeContractOwner, overrideOwner *Overrid
39
49
  }
40
50
 
41
51
  // Build converts the semantic model into the compiler IR.
42
- func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*LoweredProgram, []Diagnostic) {
52
+ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel, opts ...LoweringOptions) (*LoweredProgram, []Diagnostic) {
43
53
  if err := ctx.Err(); err != nil {
44
54
  return nil, []Diagnostic{{
45
55
  Severity: DiagnosticSeverityError,
@@ -55,7 +65,14 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*Lower
55
65
  }}
56
66
  }
57
67
 
68
+ var options LoweringOptions
69
+ if len(opts) != 0 {
70
+ options = opts[0]
71
+ }
72
+
58
73
  program := &LoweredProgram{}
74
+ lazyPackageVars := make(map[string]map[types.Object]bool, len(model.packages))
75
+ runtimeMethodSets := make(runtimeMethodSetCache)
59
76
  semPkgs := make([]*semanticPackage, 0, len(model.packages))
60
77
  for _, semPkg := range model.packages {
61
78
  semPkgs = append(semPkgs, semPkg)
@@ -70,7 +87,7 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*Lower
70
87
  diagnostics = append(diagnostics, loweringUnsupported("package", semPkg.pkgPath, "missing semantic source package"))
71
88
  continue
72
89
  }
73
- loweredPkg, pkgDiagnostics := o.lowerPackage(model, semPkg)
90
+ loweredPkg, pkgDiagnostics := o.lowerPackage(model, semPkg, lazyPackageVars, runtimeMethodSets, options)
74
91
  diagnostics = append(diagnostics, pkgDiagnostics...)
75
92
  if loweredPkg != nil {
76
93
  program.packages = append(program.packages, loweredPkg)
@@ -82,18 +99,68 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*Lower
82
99
  return program, nil
83
100
  }
84
101
 
85
- func (o *LoweringOwner) lowerPackage(model *SemanticModel, semPkg *semanticPackage) (*loweredPackage, []Diagnostic) {
102
+ func (o *LoweringOwner) lowerPackage(
103
+ model *SemanticModel,
104
+ semPkg *semanticPackage,
105
+ lazyPackageVarsByPkg map[string]map[types.Object]bool,
106
+ runtimeMethodSets runtimeMethodSetCache,
107
+ options LoweringOptions,
108
+ ) (*loweredPackage, []Diagnostic) {
86
109
  loweredPkg := &loweredPackage{
87
110
  pkgPath: semPkg.pkgPath,
88
111
  name: semPkg.name,
89
112
  }
90
113
  declFiles := packageDeclFiles(semPkg)
91
114
  outputNames := packageOutputNames(semPkg)
92
- lazyPackageVars := o.lazyPackageVars(semPkg, declFiles)
93
- var diagnostics []Diagnostic
115
+ protobufBindings, bindingDiagnostics := protobufTypeScriptBindings(semPkg, options)
116
+ for sourcePath, binding := range protobufBindings {
117
+ outputNames[sourcePath] = binding.outputName
118
+ }
119
+ lazyPackageVars := o.packageLazyVars(semPkg, lazyPackageVarsByPkg, declFiles)
120
+ diagnostics := append([]Diagnostic(nil), bindingDiagnostics...)
94
121
  for idx, file := range semPkg.source.Syntax {
95
122
  sourcePath := sourceFilePath(semPkg, idx, file)
96
- loweredFile, fileDiagnostics := o.lowerFile(model, semPkg, file, sourcePath, declFiles, outputNames, lazyPackageVars)
123
+ if options.ProtobufTypeScriptBinding && protobufSRPCHasGoScriptReplacement(sourcePath) {
124
+ stub, stubDiagnostics := lowerProtobufSRPCTypeScriptBindingStub(semPkg, sourcePath, options)
125
+ diagnostics = append(diagnostics, stubDiagnostics...)
126
+ if stub != nil {
127
+ loweredPkg.files = append(loweredPkg.files, stub)
128
+ }
129
+ continue
130
+ }
131
+ if binding, ok := protobufBindings[sourcePath]; ok {
132
+ protobufAdapter := !binding.hasOneof && !strings.HasSuffix(filepath.Base(binding.sourcePath), "_srpc.pb.go")
133
+ loweredFile, fileDiagnostics := o.lowerFile(
134
+ model,
135
+ semPkg,
136
+ file,
137
+ sourcePath,
138
+ declFiles,
139
+ outputNames,
140
+ lazyPackageVars,
141
+ lazyPackageVarsByPkg,
142
+ runtimeMethodSets,
143
+ protobufAdapter,
144
+ )
145
+ diagnostics = append(diagnostics, fileDiagnostics...)
146
+ rewriteProtobufTypeScriptBindingFile(loweredFile, binding)
147
+ if loweredFile != nil {
148
+ loweredPkg.files = append(loweredPkg.files, loweredFile)
149
+ }
150
+ continue
151
+ }
152
+ loweredFile, fileDiagnostics := o.lowerFile(
153
+ model,
154
+ semPkg,
155
+ file,
156
+ sourcePath,
157
+ declFiles,
158
+ outputNames,
159
+ lazyPackageVars,
160
+ lazyPackageVarsByPkg,
161
+ runtimeMethodSets,
162
+ false,
163
+ )
97
164
  diagnostics = append(diagnostics, fileDiagnostics...)
98
165
  if loweredFile != nil {
99
166
  loweredPkg.files = append(loweredPkg.files, loweredFile)
@@ -125,6 +192,9 @@ func (o *LoweringOwner) lowerFile(
125
192
  declFiles map[types.Object]string,
126
193
  outputNames map[string]string,
127
194
  lazyPackageVars map[types.Object]bool,
195
+ lazyPackageVarsByPkg map[string]map[types.Object]bool,
196
+ runtimeMethodSets runtimeMethodSetCache,
197
+ protobufTypeScriptAdapter bool,
128
198
  ) (*loweredFile, []Diagnostic) {
129
199
  associatedMethods := o.methodDeclsForFileTypes(semPkg, file)
130
200
  relevantImportFiles := map[string]bool{sourcePath: true}
@@ -146,7 +216,7 @@ func (o *LoweringOwner) lowerFile(
146
216
  importPaths := make(map[string]string)
147
217
  importNames := make(map[string]string)
148
218
  importObjects := make(map[*types.PkgName]string)
149
- localRefs := o.analyzeLocalFileReferences(semPkg, file, sourcePath, associatedMethods, declFiles, outputNames)
219
+ localRefs := o.analyzeLocalFileReferences(semPkg, file, sourcePath, associatedMethods, declFiles, outputNames, runtimeMethodSets)
150
220
  reservedImportAliases := localRefs.reservedNames
151
221
  seenImport := make(map[string]bool)
152
222
  for idx, importFile := range semPkg.source.Syntax {
@@ -231,18 +301,20 @@ func (o *LoweringOwner) lowerFile(
231
301
  loweredFile.imports = append(loweredFile.imports, localImports...)
232
302
 
233
303
  ctx := lowerFileContext{
234
- model: model,
235
- semPkg: semPkg,
236
- file: file,
237
- importAliases: importAliases,
238
- importPaths: importPaths,
239
- importNames: importNames,
240
- importObjects: importObjects,
241
- sourcePath: sourcePath,
242
- localAliases: localRefs.aliases,
243
- lazyPackageVars: lazyPackageVars,
244
- tempNames: newTempNameOwner(),
245
- topLevel: true,
304
+ model: model,
305
+ semPkg: semPkg,
306
+ file: file,
307
+ importAliases: importAliases,
308
+ importPaths: importPaths,
309
+ importNames: importNames,
310
+ importObjects: importObjects,
311
+ sourcePath: sourcePath,
312
+ localAliases: localRefs.aliases,
313
+ lazyPackageVars: lazyPackageVars,
314
+ lazyPackageVarsByPkg: lazyPackageVarsByPkg,
315
+ tempNames: newTempNameOwner(),
316
+ topLevel: true,
317
+ protobufTSAdapter: protobufTypeScriptAdapter,
246
318
  }
247
319
  var diagnostics []Diagnostic
248
320
  var packageInitCalls []string
@@ -451,6 +523,24 @@ type localFileReferenceAnalysis struct {
451
523
  implicitRuntime map[string]bool
452
524
  }
453
525
 
526
+ type runtimeMethodSetCache map[*types.Named][]types.Object
527
+
528
+ func (c runtimeMethodSetCache) methods(named *types.Named) []types.Object {
529
+ if named == nil {
530
+ return nil
531
+ }
532
+ if methods, ok := c[named]; ok {
533
+ return methods
534
+ }
535
+ methodSet := types.NewMethodSet(types.NewPointer(named))
536
+ methods := make([]types.Object, 0, methodSet.Len())
537
+ for method := range methodSet.Methods() {
538
+ methods = append(methods, method.Obj())
539
+ }
540
+ c[named] = methods
541
+ return methods
542
+ }
543
+
454
544
  func (o *LoweringOwner) analyzeLocalFileReferences(
455
545
  semPkg *semanticPackage,
456
546
  file *ast.File,
@@ -458,6 +548,7 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
458
548
  associatedMethods []*ast.FuncDecl,
459
549
  declFiles map[types.Object]string,
460
550
  outputNames map[string]string,
551
+ runtimeMethodSets runtimeMethodSetCache,
461
552
  ) localFileReferenceAnalysis {
462
553
  analysis := localFileReferenceAnalysis{
463
554
  reservedNames: make(map[string]bool),
@@ -469,6 +560,8 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
469
560
  }
470
561
  seenObjects := make(map[types.Object]bool)
471
562
  seenTypes := make(map[types.Type]bool)
563
+ seenRuntimeTypes := make(map[types.Type]bool)
564
+ seenRuntimeOwnerTypes := make(map[types.Type]bool)
472
565
  var addTypeDeps func(typ types.Type)
473
566
  var addRuntimeTypeDeps func(typ types.Type)
474
567
  var addRuntimeTypeOwnerDeps func(typ types.Type)
@@ -636,6 +729,10 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
636
729
  if typ == nil {
637
730
  return
638
731
  }
732
+ if seenRuntimeTypes[typ] {
733
+ return
734
+ }
735
+ seenRuntimeTypes[typ] = true
639
736
  if alias, ok := typ.(*types.Alias); ok {
640
737
  addObject(alias.Obj(), true)
641
738
  if args := alias.TypeArgs(); args != nil {
@@ -651,9 +748,8 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
651
748
  for method := range named.Methods() {
652
749
  addObject(method, true)
653
750
  }
654
- methodSet := types.NewMethodSet(types.NewPointer(named))
655
- for method := range methodSet.Methods() {
656
- addObject(method.Obj(), true)
751
+ for _, method := range runtimeMethodSets.methods(named) {
752
+ addObject(method, true)
657
753
  }
658
754
  if args := named.TypeArgs(); args != nil {
659
755
  for t := range args.Types() {
@@ -680,6 +776,10 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
680
776
  if typ == nil {
681
777
  return
682
778
  }
779
+ if seenRuntimeOwnerTypes[typ] {
780
+ return
781
+ }
782
+ seenRuntimeOwnerTypes[typ] = true
683
783
  if alias, ok := typ.(*types.Alias); ok {
684
784
  addObject(alias.Obj(), true)
685
785
  if args := alias.TypeArgs(); args != nil {
@@ -773,6 +873,9 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
773
873
  }
774
874
  ast.Inspect(file, inspect)
775
875
  for _, methodDecl := range associatedMethods {
876
+ if sourcePos(semPkg.source, methodDecl.Pos()).file == sourcePath {
877
+ continue
878
+ }
776
879
  ast.Inspect(methodDecl, inspect)
777
880
  }
778
881
  return analysis
@@ -984,36 +1087,39 @@ func safeParamName(param *types.Var, idx int) string {
984
1087
  }
985
1088
 
986
1089
  type lowerFileContext struct {
987
- model *SemanticModel
988
- semPkg *semanticPackage
989
- file *ast.File
990
- importAliases map[string]string
991
- importPaths map[string]string
992
- importNames map[string]string
993
- importObjects map[*types.PkgName]string
994
- sourcePath string
995
- localAliases map[types.Object]string
996
- lazyPackageVars map[types.Object]bool
997
- identAliases map[types.Object]string
998
- identAliasRefs map[types.Object]bool
999
- tempNames *tempNameOwner
1000
- signature *types.Signature
1001
- typeParams map[string]bool
1002
- staticTypeParams map[string]bool
1003
- asyncFunction bool
1004
- functionTypeDepth int
1005
- deferState *loweredDeferState
1006
- rangeBranch *loweredRangeBranch
1007
- rangeBreak bool
1008
- rangeContinue bool
1009
- gotoLabels map[string]bool
1010
- forwardGotos map[string]bool
1011
- gotoStateLabels map[string]bool
1012
- gotoStateVar string
1013
- gotoStateLoop string
1014
- loopLabel string
1015
- switchBreak bool
1016
- topLevel bool
1090
+ model *SemanticModel
1091
+ semPkg *semanticPackage
1092
+ file *ast.File
1093
+ importAliases map[string]string
1094
+ importPaths map[string]string
1095
+ importNames map[string]string
1096
+ importObjects map[*types.PkgName]string
1097
+ sourcePath string
1098
+ localAliases map[types.Object]string
1099
+ lazyPackageVars map[types.Object]bool
1100
+ lazyPackageVarsByPkg map[string]map[types.Object]bool
1101
+ identAliases map[types.Object]string
1102
+ identAliasRefs map[types.Object]bool
1103
+ tempNames *tempNameOwner
1104
+ signature *types.Signature
1105
+ typeParams map[string]bool
1106
+ staticTypeParams map[string]bool
1107
+ asyncFunction bool
1108
+ functionTypeDepth int
1109
+ deferState *loweredDeferState
1110
+ rangeBranch *loweredRangeBranch
1111
+ rangeBreak bool
1112
+ rangeContinue bool
1113
+ gotoLabels map[string]bool
1114
+ forwardGotos map[string]bool
1115
+ gotoStateLabels map[string]bool
1116
+ gotoStateVar string
1117
+ gotoStateLoop string
1118
+ functionScopedDecls bool
1119
+ loopLabel string
1120
+ switchBreak bool
1121
+ topLevel bool
1122
+ protobufTSAdapter bool
1017
1123
  }
1018
1124
 
1019
1125
  type tempNameOwner struct {
@@ -1124,7 +1230,7 @@ func isConstGenDecl(decl ast.Decl) bool {
1124
1230
  }
1125
1231
 
1126
1232
  func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([]loweredDecl, []Diagnostic) {
1127
- var decls []loweredDecl
1233
+ decls := make([]loweredDecl, 0, len(decl.Specs))
1128
1234
  var diagnostics []Diagnostic
1129
1235
  for _, spec := range decl.Specs {
1130
1236
  switch typed := spec.(type) {
@@ -1171,7 +1277,7 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
1171
1277
  if _, ok := obj.(*types.Const); !ok && ctx.model.needsVarRef[obj] {
1172
1278
  value = o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(" + value + ")"
1173
1279
  }
1174
- keyword := "let"
1280
+ keyword := strings.TrimSpace(declarationKeyword(ctx))
1175
1281
  if _, ok := obj.(*types.Const); ok || decl.Tok == token.CONST {
1176
1282
  keyword = "const"
1177
1283
  }
@@ -1190,7 +1296,7 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
1190
1296
  code := keyword + " " + declName + ": " + variableType + " = " + value
1191
1297
  if lazy {
1192
1298
  keyword = "var"
1193
- code = "var " + declName + ": " + variableType + " = undefined as unknown as " + variableType
1299
+ code = "var " + declName + ": " + variableType
1194
1300
  }
1195
1301
  indexExport := ""
1196
1302
  if ctx.topLevel && name.Name != "_" {
@@ -1402,7 +1508,10 @@ func packageDeclFiles(semPkg *semanticPackage) map[types.Object]string {
1402
1508
  if semPkg == nil || semPkg.source == nil {
1403
1509
  return nil
1404
1510
  }
1405
- declFiles := make(map[types.Object]string)
1511
+ if len(semPkg.source.Syntax) <= 1 {
1512
+ return nil
1513
+ }
1514
+ declFiles := make(map[types.Object]string, len(semPkg.declarations))
1406
1515
  for _, decl := range semPkg.declarations {
1407
1516
  if decl.object != nil && decl.position.file != "" {
1408
1517
  declFiles[decl.object] = decl.position.file
@@ -1423,6 +1532,31 @@ func packageOutputNames(semPkg *semanticPackage) map[string]string {
1423
1532
  return outputNames
1424
1533
  }
1425
1534
 
1535
+ func (o *LoweringOwner) packageLazyVars(
1536
+ semPkg *semanticPackage,
1537
+ cache map[string]map[types.Object]bool,
1538
+ declFiles map[types.Object]string,
1539
+ ) map[types.Object]bool {
1540
+ if semPkg == nil {
1541
+ return nil
1542
+ }
1543
+ if cache == nil {
1544
+ if declFiles == nil {
1545
+ declFiles = packageDeclFiles(semPkg)
1546
+ }
1547
+ return o.lazyPackageVars(semPkg, declFiles)
1548
+ }
1549
+ if lazy, ok := cache[semPkg.pkgPath]; ok {
1550
+ return lazy
1551
+ }
1552
+ if declFiles == nil {
1553
+ declFiles = packageDeclFiles(semPkg)
1554
+ }
1555
+ lazy := o.lazyPackageVars(semPkg, declFiles)
1556
+ cache[semPkg.pkgPath] = lazy
1557
+ return lazy
1558
+ }
1559
+
1426
1560
  func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage, declFiles map[types.Object]string) map[types.Object]bool {
1427
1561
  if semPkg == nil || semPkg.source == nil {
1428
1562
  return nil
@@ -1589,7 +1723,7 @@ func (o *LoweringOwner) packageVarIsLazy(ctx lowerFileContext, obj *types.Var) b
1589
1723
  if semPkg == nil {
1590
1724
  return false
1591
1725
  }
1592
- for lazyObj := range o.lazyPackageVars(semPkg, packageDeclFiles(semPkg)) {
1726
+ for lazyObj := range o.packageLazyVars(semPkg, ctx.lazyPackageVarsByPkg, nil) {
1593
1727
  if lazyObj != nil && lazyObj.Name() == obj.Name() &&
1594
1728
  lazyObj.Pkg() != nil && lazyObj.Pkg().Path() == obj.Pkg().Path() {
1595
1729
  return true
@@ -1606,7 +1740,7 @@ func (o *LoweringOwner) packageVarNameIsLazy(ctx lowerFileContext, pkgPath, name
1606
1740
  if semPkg == nil {
1607
1741
  return false
1608
1742
  }
1609
- for lazyObj := range o.lazyPackageVars(semPkg, packageDeclFiles(semPkg)) {
1743
+ for lazyObj := range o.packageLazyVars(semPkg, ctx.lazyPackageVarsByPkg, nil) {
1610
1744
  if lazyObj != nil && lazyObj.Name() == name {
1611
1745
  return true
1612
1746
  }
@@ -1962,6 +2096,13 @@ func lowerLargeIntegerConstantValue(value constant.Value) (string, bool) {
1962
2096
  return value.ExactString(), true
1963
2097
  }
1964
2098
 
2099
+ func lowerWideIntegerConstantValue(value constant.Value) (string, bool) {
2100
+ if value == nil || value.Kind() != constant.Int || constant.BitLen(value) <= 53 {
2101
+ return "", false
2102
+ }
2103
+ return value.ExactString(), true
2104
+ }
2105
+
1965
2106
  func lowerConstantStringByteSlice(ctx lowerFileContext, expr ast.Expr) (string, bool) {
1966
2107
  value := ctx.semPkg.source.TypesInfo.Types[unwrapParenExpr(expr)].Value
1967
2108
  if value == nil || value.Kind() != constant.String {
@@ -2006,35 +2147,218 @@ func (o *LoweringOwner) lowerGoEmbedValue(
2006
2147
  typ types.Type,
2007
2148
  patterns []string,
2008
2149
  ) (string, []Diagnostic) {
2150
+ if isEmbedFSType(typ) {
2151
+ return o.lowerGoEmbedFSValue(ctx, patterns)
2152
+ }
2009
2153
  if len(patterns) != 1 {
2010
2154
  return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2011
2155
  }
2012
- pattern := strings.Trim(patterns[0], "`\"")
2156
+ cleanPattern, diagnostics := cleanGoEmbedFilePattern(ctx, patterns[0])
2157
+ if len(diagnostics) != 0 {
2158
+ return "", diagnostics
2159
+ }
2160
+ data, diagnostics := readGoEmbedFile(ctx, cleanPattern)
2161
+ if len(diagnostics) != 0 {
2162
+ return "", diagnostics
2163
+ }
2164
+ if isStringType(typ) {
2165
+ return strconv.Quote(string(data)), nil
2166
+ }
2167
+ if slice, ok := types.Unalias(typ).Underlying().(*types.Slice); ok && isByteType(slice.Elem()) {
2168
+ return byteSliceLiteral(data), nil
2169
+ }
2170
+ diag := loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed target type")
2171
+ diag.Detail = "target type: " + types.TypeString(typ, func(pkg *types.Package) string {
2172
+ if pkg == nil {
2173
+ return ""
2174
+ }
2175
+ return pkg.Path()
2176
+ })
2177
+ return "", []Diagnostic{diag}
2178
+ }
2179
+
2180
+ func (o *LoweringOwner) lowerGoEmbedFSValue(ctx lowerFileContext, patterns []string) (string, []Diagnostic) {
2181
+ embedAlias := ctx.importPaths["embed"]
2182
+ if embedAlias == "" {
2183
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed FS import")}
2184
+ }
2185
+ if len(patterns) == 0 {
2186
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2187
+ }
2188
+
2189
+ filesByPath := make(map[string][]byte)
2190
+ for _, pattern := range patterns {
2191
+ files, diagnostics := expandGoEmbedPattern(ctx, pattern)
2192
+ if len(diagnostics) != 0 {
2193
+ return "", diagnostics
2194
+ }
2195
+ for _, file := range files {
2196
+ filesByPath[file.path] = file.data
2197
+ }
2198
+ }
2199
+ paths := make([]string, 0, len(filesByPath))
2200
+ for path := range filesByPath {
2201
+ paths = append(paths, path)
2202
+ }
2203
+ slices.Sort(paths)
2204
+ entries := make([]string, 0, len(paths))
2205
+ for _, path := range paths {
2206
+ entries = append(entries, "["+strconv.Quote(path)+", "+byteSliceLiteral(filesByPath[path])+"]")
2207
+ }
2208
+ builtinAlias := o.runtimeOwner.BuiltinImport().Alias
2209
+ return builtinAlias + ".markAsStructValue(new " + embedAlias + ".FS(new Map<string, Uint8Array>([" + strings.Join(entries, ", ") + "])))", nil
2210
+ }
2211
+
2212
+ type goEmbedFile struct {
2213
+ path string
2214
+ data []byte
2215
+ }
2216
+
2217
+ func cleanGoEmbedFilePattern(ctx lowerFileContext, pattern string) (string, []Diagnostic) {
2218
+ cleanPattern, _, diagnostics := cleanGoEmbedPattern(ctx, pattern)
2219
+ if len(diagnostics) != 0 {
2220
+ return "", diagnostics
2221
+ }
2222
+ if strings.Contains(cleanPattern, "*") {
2223
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2224
+ }
2225
+ info, err := os.Stat(filepath.Join(filepath.Dir(ctx.sourcePath), filepath.FromSlash(cleanPattern)))
2226
+ if err != nil {
2227
+ return "", []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2228
+ }
2229
+ if info.IsDir() {
2230
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed directory target")}
2231
+ }
2232
+ return cleanPattern, nil
2233
+ }
2234
+
2235
+ func cleanGoEmbedPattern(ctx lowerFileContext, pattern string) (string, bool, []Diagnostic) {
2236
+ pattern = strings.Trim(pattern, "`\"")
2237
+ all := false
2238
+ if strings.HasPrefix(pattern, "all:") {
2239
+ all = true
2240
+ pattern = strings.TrimPrefix(pattern, "all:")
2241
+ }
2013
2242
  cleanPattern := path.Clean(pattern)
2014
2243
  if pattern == "" ||
2015
- strings.Contains(pattern, "*") ||
2016
2244
  path.IsAbs(pattern) ||
2017
2245
  cleanPattern == "." ||
2018
2246
  cleanPattern == ".." ||
2019
2247
  strings.HasPrefix(cleanPattern, "../") {
2020
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2248
+ return "", false, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2021
2249
  }
2022
- data, err := os.ReadFile(filepath.Join(filepath.Dir(ctx.sourcePath), filepath.FromSlash(cleanPattern)))
2250
+ return cleanPattern, all, nil
2251
+ }
2252
+
2253
+ func expandGoEmbedPattern(ctx lowerFileContext, pattern string) ([]goEmbedFile, []Diagnostic) {
2254
+ cleanPattern, all, diagnostics := cleanGoEmbedPattern(ctx, pattern)
2255
+ if len(diagnostics) != 0 {
2256
+ return nil, diagnostics
2257
+ }
2258
+ pkgDir := filepath.Dir(ctx.sourcePath)
2259
+ paths := []string{filepath.Join(pkgDir, filepath.FromSlash(cleanPattern))}
2260
+ if strings.Contains(cleanPattern, "*") {
2261
+ matches, err := filepath.Glob(filepath.Join(pkgDir, filepath.FromSlash(cleanPattern)))
2262
+ if err != nil {
2263
+ return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2264
+ }
2265
+ if len(matches) == 0 {
2266
+ return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "go:embed pattern matched no files")}
2267
+ }
2268
+ paths = matches
2269
+ }
2270
+
2271
+ var files []goEmbedFile
2272
+ for _, path := range paths {
2273
+ collected, diagnostics := collectGoEmbedPath(ctx, pkgDir, path, all)
2274
+ if len(diagnostics) != 0 {
2275
+ return nil, diagnostics
2276
+ }
2277
+ files = append(files, collected...)
2278
+ }
2279
+ slices.SortFunc(files, func(a, b goEmbedFile) int {
2280
+ return cmp.Compare(a.path, b.path)
2281
+ })
2282
+ return files, nil
2283
+ }
2284
+
2285
+ func collectGoEmbedPath(ctx lowerFileContext, pkgDir, absPath string, all bool) ([]goEmbedFile, []Diagnostic) {
2286
+ info, err := os.Stat(absPath)
2023
2287
  if err != nil {
2024
- return "", []Diagnostic{{
2025
- Severity: DiagnosticSeverityError,
2026
- Code: "goscript/lowering:embed",
2027
- Message: "failed to read go:embed file",
2028
- Detail: ctx.semPkg.pkgPath + ": " + err.Error(),
2029
- }}
2288
+ return nil, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2030
2289
  }
2031
- if isStringType(typ) {
2032
- return strconv.Quote(string(data)), nil
2290
+ if !info.IsDir() {
2291
+ file, diagnostics := readGoEmbedAbsFile(ctx, pkgDir, absPath)
2292
+ if len(diagnostics) != 0 {
2293
+ return nil, diagnostics
2294
+ }
2295
+ return []goEmbedFile{file}, nil
2033
2296
  }
2034
- if slice, ok := types.Unalias(typ).Underlying().(*types.Slice); ok && isByteType(slice.Elem()) {
2035
- return byteSliceLiteral(data), nil
2297
+
2298
+ var files []goEmbedFile
2299
+ if err := filepath.WalkDir(absPath, func(path string, entry os.DirEntry, err error) error {
2300
+ if err != nil {
2301
+ return err
2302
+ }
2303
+ if path != absPath && !all && (strings.HasPrefix(entry.Name(), ".") || strings.HasPrefix(entry.Name(), "_")) {
2304
+ if entry.IsDir() {
2305
+ return filepath.SkipDir
2306
+ }
2307
+ return nil
2308
+ }
2309
+ if entry.IsDir() {
2310
+ return nil
2311
+ }
2312
+ file, diagnostics := readGoEmbedAbsFile(ctx, pkgDir, path)
2313
+ if len(diagnostics) != 0 {
2314
+ return fmt.Errorf("%s", diagnostics[0].Detail)
2315
+ }
2316
+ files = append(files, file)
2317
+ return nil
2318
+ }); err != nil {
2319
+ return nil, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2320
+ }
2321
+ if len(files) == 0 {
2322
+ return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "go:embed directory matched no files")}
2323
+ }
2324
+ return files, nil
2325
+ }
2326
+
2327
+ func readGoEmbedFile(ctx lowerFileContext, cleanPattern string) ([]byte, []Diagnostic) {
2328
+ file, diagnostics := readGoEmbedAbsFile(ctx, filepath.Dir(ctx.sourcePath), filepath.Join(filepath.Dir(ctx.sourcePath), filepath.FromSlash(cleanPattern)))
2329
+ if len(diagnostics) != 0 {
2330
+ return nil, diagnostics
2331
+ }
2332
+ return file.data, nil
2333
+ }
2334
+
2335
+ func readGoEmbedAbsFile(ctx lowerFileContext, pkgDir, absPath string) (goEmbedFile, []Diagnostic) {
2336
+ relPath, err := filepath.Rel(pkgDir, absPath)
2337
+ if err != nil {
2338
+ return goEmbedFile{}, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2339
+ }
2340
+ data, err := os.ReadFile(absPath)
2341
+ if err != nil {
2342
+ return goEmbedFile{}, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2343
+ }
2344
+ return goEmbedFile{path: filepath.ToSlash(relPath), data: data}, nil
2345
+ }
2346
+
2347
+ func goEmbedReadDiagnostic(ctx lowerFileContext, err error) Diagnostic {
2348
+ return Diagnostic{
2349
+ Severity: DiagnosticSeverityError,
2350
+ Code: "goscript/lowering:embed",
2351
+ Message: "failed to read go:embed file",
2352
+ Detail: ctx.semPkg.pkgPath + ": " + err.Error(),
2036
2353
  }
2037
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed target type")}
2354
+ }
2355
+
2356
+ func isEmbedFSType(typ types.Type) bool {
2357
+ named, _ := types.Unalias(typ).(*types.Named)
2358
+ if named == nil || named.Obj() == nil || named.Obj().Pkg() == nil {
2359
+ return false
2360
+ }
2361
+ return named.Obj().Pkg().Path() == "embed" && named.Obj().Name() == "FS"
2038
2362
  }
2039
2363
 
2040
2364
  func byteSliceLiteral(data []byte) string {
@@ -2202,6 +2526,7 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2202
2526
  name: safeIdentifier(semType.name),
2203
2527
  typeName: runtimeNamedTypeName(semType.named),
2204
2528
  cloneMethod: "clone",
2529
+ fields: make([]loweredStructField, 0, len(semType.fields)),
2205
2530
  }
2206
2531
  for idx, field := range semType.fields {
2207
2532
  structValue := isStructValueType(field.typ)
@@ -2221,6 +2546,11 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2221
2546
  runtimeType: o.runtimeTypeInfoExpr(field.typ),
2222
2547
  doc: field.doc,
2223
2548
  tag: field.tag,
2549
+ pkgPath: field.pkgPath,
2550
+ index: field.index,
2551
+ offset: field.offset,
2552
+ anonymous: field.embedded,
2553
+ exported: field.exported,
2224
2554
  structValue: structValue,
2225
2555
  arrayValue: isArrayType(field.typ),
2226
2556
  })
@@ -2228,14 +2558,23 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2228
2558
 
2229
2559
  methodDecls := o.methodDeclsForType(ctx, semType.named)
2230
2560
  explicitMethods := make(map[string]bool, len(methodDecls))
2231
- for _, methodDecl := range methodDecls {
2232
- if methodDecl != nil {
2233
- explicitMethods[methodDecl.Name.Name] = true
2561
+ if len(methodDecls) != 0 {
2562
+ lowered.methods = make([]loweredFunction, 0, len(methodDecls))
2563
+ for _, methodDecl := range methodDecls {
2564
+ if methodDecl != nil {
2565
+ explicitMethods[methodDecl.Name.Name] = true
2566
+ }
2234
2567
  }
2235
2568
  }
2236
2569
  var diagnostics []Diagnostic
2237
2570
  for _, methodDecl := range methodDecls {
2238
- method, methodDiagnostics := o.lowerFuncDecl(ctx, methodDecl)
2571
+ lowerDecl := methodDecl
2572
+ if ctx.protobufTSAdapter && protobufTypeScriptBindingReplacesMethodName(methodDecl.Name.Name) {
2573
+ bodyless := *methodDecl
2574
+ bodyless.Body = nil
2575
+ lowerDecl = &bodyless
2576
+ }
2577
+ method, methodDiagnostics := o.lowerFuncDecl(ctx, lowerDecl)
2239
2578
  diagnostics = append(diagnostics, methodDiagnostics...)
2240
2579
  if method != nil {
2241
2580
  if method.name == "clone" {
@@ -2287,11 +2626,12 @@ func (o *LoweringOwner) lowerEmbeddedMethodForwarders(
2287
2626
  async := o.functionAsync(ctx, method)
2288
2627
  targetType := o.tsEmbeddedForwarderTargetType(ctx, field.typ)
2289
2628
  lowered := loweredFunction{
2290
- async: async,
2291
- name: methodMemberName(method.Name()),
2292
- runtimeName: method.Name(),
2293
- result: asyncResultType("any", async),
2294
- deferState: &loweredDeferState{},
2629
+ async: async,
2630
+ name: methodMemberName(method.Name()),
2631
+ runtimeName: method.Name(),
2632
+ runtimeSignature: o.runtimeMethodSignature(method, make(map[types.Type]bool)),
2633
+ result: asyncResultType("any", async),
2634
+ deferState: &loweredDeferState{},
2295
2635
  }
2296
2636
  args := make([]string, 0, signature.Params().Len())
2297
2637
  for idx := range signature.Params().Len() {
@@ -2510,6 +2850,9 @@ func (o *LoweringOwner) lowerFuncDecl(ctx lowerFileContext, decl *ast.FuncDecl)
2510
2850
  deferState: deferState,
2511
2851
  namedResults: o.lowerNamedResults(functionCtx, signature),
2512
2852
  }
2853
+ if decl.Recv != nil {
2854
+ lowered.runtimeSignature = o.runtimeMethodSignature(fnObj, make(map[types.Type]bool))
2855
+ }
2513
2856
  if signature.TypeParams() != nil && signature.TypeParams().Len() != 0 {
2514
2857
  lowered.typeParams = signatureTypeParamNames(signature)
2515
2858
  lowered.params = append(lowered.params, loweredParam{
@@ -2652,6 +2995,9 @@ func expressionUsesObject(ctx lowerFileContext, expr ast.Expr, obj types.Object)
2652
2995
  if expr == nil || obj == nil || ctx.semPkg == nil || ctx.semPkg.source == nil {
2653
2996
  return false
2654
2997
  }
2998
+ if ident, ok := ast.Unparen(expr).(*ast.Ident); ok {
2999
+ return ctx.semPkg.source.TypesInfo.Uses[ident] == obj || ctx.semPkg.source.TypesInfo.Defs[ident] == obj
3000
+ }
2655
3001
  uses := false
2656
3002
  ast.Inspect(expr, func(node ast.Node) bool {
2657
3003
  if uses {
@@ -2731,9 +3077,22 @@ func (ctx lowerFileContext) withDeferState(deferState *loweredDeferState) lowerF
2731
3077
 
2732
3078
  func (ctx lowerFileContext) withLocalScope() lowerFileContext {
2733
3079
  ctx.topLevel = false
3080
+ ctx.functionScopedDecls = false
3081
+ return ctx
3082
+ }
3083
+
3084
+ func (ctx lowerFileContext) withFunctionScopedDecls() lowerFileContext {
3085
+ ctx.functionScopedDecls = true
2734
3086
  return ctx
2735
3087
  }
2736
3088
 
3089
+ func declarationKeyword(ctx lowerFileContext) string {
3090
+ if ctx.functionScopedDecls {
3091
+ return "var "
3092
+ }
3093
+ return "let "
3094
+ }
3095
+
2737
3096
  func (ctx lowerFileContext) withRangeBranch(branch *loweredRangeBranch) lowerFileContext {
2738
3097
  ctx.rangeBranch = branch
2739
3098
  ctx.rangeBreak = true
@@ -2821,6 +3180,10 @@ func (o *LoweringOwner) lowerBlock(ctx lowerFileContext, block *ast.BlockStmt) (
2821
3180
  }
2822
3181
 
2823
3182
  func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]loweredStmt, []Diagnostic) {
3183
+ return o.lowerStmtInto(ctx, stmt, nil)
3184
+ }
3185
+
3186
+ func (o *LoweringOwner) lowerStmtInto(ctx lowerFileContext, stmt ast.Stmt, out []loweredStmt) ([]loweredStmt, []Diagnostic) {
2824
3187
  switch typed := stmt.(type) {
2825
3188
  case *ast.DeclStmt:
2826
3189
  decls, diagnostics := o.lowerDecl(ctx, typed.Decl)
@@ -2836,27 +3199,28 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
2836
3199
  stmts = append(stmts, loweredStmt{text: strings.TrimRight(b.String(), "\n")})
2837
3200
  }
2838
3201
  }
2839
- return stmts, diagnostics
3202
+ return append(out, stmts...), diagnostics
2840
3203
  case *ast.BlockStmt:
2841
3204
  body, diagnostics := o.lowerBlock(ctx, typed)
2842
- return []loweredStmt{{hasBlock: true, children: body}}, diagnostics
3205
+ return append(out, loweredStmt{hasBlock: true, children: body}), diagnostics
2843
3206
  case *ast.AssignStmt:
2844
- return o.lowerAssignStmt(ctx, typed)
3207
+ stmts, diagnostics := o.lowerAssignStmt(ctx, typed)
3208
+ return append(out, stmts...), diagnostics
2845
3209
  case *ast.SendStmt:
2846
3210
  text, diagnostics := o.lowerSendStmt(ctx, typed)
2847
- return []loweredStmt{{text: text}}, diagnostics
3211
+ return append(out, loweredStmt{text: text}), diagnostics
2848
3212
  case *ast.GoStmt:
2849
3213
  text, diagnostics := o.lowerGoStmt(ctx, typed)
2850
- return []loweredStmt{{text: text}}, diagnostics
3214
+ return append(out, loweredStmt{text: text}), diagnostics
2851
3215
  case *ast.DeferStmt:
2852
3216
  text, diagnostics := o.lowerDeferStmt(ctx, typed)
2853
- return []loweredStmt{{text: text}}, diagnostics
3217
+ return append(out, loweredStmt{text: text}), diagnostics
2854
3218
  case *ast.ExprStmt:
2855
3219
  text, diagnostics := o.lowerExpr(ctx, typed.X)
2856
- return []loweredStmt{{text: expressionStmtText(text)}}, diagnostics
3220
+ return append(out, loweredStmt{text: expressionStmtText(text)}), diagnostics
2857
3221
  case *ast.ReturnStmt:
2858
3222
  text, diagnostics := o.lowerReturnStmt(ctx, typed)
2859
- return []loweredStmt{{text: text}}, diagnostics
3223
+ return append(out, loweredStmt{text: text}), diagnostics
2860
3224
  case *ast.IfStmt:
2861
3225
  var diagnostics []Diagnostic
2862
3226
  var init []loweredStmt
@@ -2889,39 +3253,43 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
2889
3253
  }
2890
3254
  if len(init) != 0 {
2891
3255
  init = append(init, stmt)
2892
- return append(initPrelude, loweredStmt{children: init}), diagnostics
3256
+ initPrelude = append(initPrelude, loweredStmt{children: init})
3257
+ return append(out, initPrelude...), diagnostics
2893
3258
  }
2894
- return []loweredStmt{stmt}, diagnostics
3259
+ return append(out, stmt), diagnostics
2895
3260
  case *ast.ForStmt:
2896
3261
  lowered, diagnostics := o.lowerForStmt(ctx, typed)
2897
- return []loweredStmt{lowered}, diagnostics
3262
+ return append(out, lowered), diagnostics
2898
3263
  case *ast.RangeStmt:
2899
3264
  lowered, diagnostics := o.lowerRangeStmt(ctx, typed)
2900
- return []loweredStmt{lowered}, diagnostics
3265
+ return append(out, lowered), diagnostics
2901
3266
  case *ast.SelectStmt:
2902
3267
  lowered, diagnostics := o.lowerSelectStmt(ctx, typed)
2903
- return []loweredStmt{{selectStmt: lowered}}, diagnostics
3268
+ return append(out, loweredStmt{selectStmt: lowered}), diagnostics
2904
3269
  case *ast.SwitchStmt:
2905
- return o.lowerSwitchStmt(ctx, typed)
3270
+ stmts, diagnostics := o.lowerSwitchStmt(ctx, typed)
3271
+ return append(out, stmts...), diagnostics
2906
3272
  case *ast.TypeSwitchStmt:
2907
- return o.lowerTypeSwitchStmt(ctx, typed)
3273
+ stmts, diagnostics := o.lowerTypeSwitchStmt(ctx, typed)
3274
+ return append(out, stmts...), diagnostics
2908
3275
  case *ast.LabeledStmt:
2909
3276
  lowered, diagnostics := o.lowerStmt(ctx, typed.Stmt)
2910
3277
  if len(lowered) != 0 {
2911
3278
  label := safeIdentifier(typed.Label.Name)
2912
3279
  if lowered[0].text == "" {
2913
- return []loweredStmt{{text: label + ":", children: lowered}}, diagnostics
3280
+ return append(out, loweredStmt{text: label + ":", children: lowered}), diagnostics
2914
3281
  }
2915
3282
  if labeledTextCannotPrefix(lowered[0].text) {
2916
- return append([]loweredStmt{{text: label + ":;"}}, lowered...), diagnostics
3283
+ out = append(out, loweredStmt{text: label + ":;"})
3284
+ return append(out, lowered...), diagnostics
2917
3285
  }
2918
3286
  lowered[0].text = label + ": " + lowered[0].text
2919
3287
  }
2920
- return lowered, diagnostics
3288
+ return append(out, lowered...), diagnostics
2921
3289
  case *ast.IncDecStmt:
2922
3290
  if star, ok := unwrapParenExpr(typed.X).(*ast.StarExpr); ok {
2923
3291
  expr, diagnostics := o.lowerPointerStorageExpr(ctx, star.X)
2924
- return []loweredStmt{{text: expr + typed.Tok.String()}}, diagnostics
3292
+ return append(out, loweredStmt{text: expr + typed.Tok.String()}), diagnostics
2925
3293
  }
2926
3294
  if index, ok := unwrapParenExpr(typed.X).(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) {
2927
3295
  right := "1"
@@ -2929,7 +3297,8 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
2929
3297
  if typed.Tok == token.DEC {
2930
3298
  tok = token.SUB_ASSIGN
2931
3299
  }
2932
- return o.lowerMapIndexUpdateStmts(ctx, index, tok, right, ctx.semPkg.source.TypesInfo.TypeOf(typed.X))
3300
+ stmts, diagnostics := o.lowerMapIndexUpdateStmts(ctx, index, tok, right, ctx.semPkg.source.TypesInfo.TypeOf(typed.X))
3301
+ return append(out, stmts...), diagnostics
2933
3302
  }
2934
3303
  if setter, ok := o.packageVarSetterForAssignment(ctx, typed.X); ok {
2935
3304
  expr, diagnostics := o.lowerExpr(ctx, typed.X)
@@ -2937,58 +3306,58 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
2937
3306
  if typed.Tok == token.DEC {
2938
3307
  op = "-"
2939
3308
  }
2940
- return []loweredStmt{{text: setter + "(" + expr + " " + op + " 1)"}}, diagnostics
3309
+ return append(out, loweredStmt{text: setter + "(" + expr + " " + op + " 1)"}), diagnostics
2941
3310
  }
2942
3311
  expr, diagnostics := o.lowerExpr(ctx, typed.X)
2943
- return []loweredStmt{{text: expr + typed.Tok.String()}}, diagnostics
3312
+ return append(out, loweredStmt{text: expr + typed.Tok.String()}), diagnostics
2944
3313
  case *ast.BranchStmt:
2945
3314
  if typed.Label != nil {
2946
3315
  switch typed.Tok {
2947
3316
  case token.BREAK, token.CONTINUE:
2948
- return []loweredStmt{{text: typed.Tok.String() + " " + safeIdentifier(typed.Label.Name)}}, nil
3317
+ return append(out, loweredStmt{text: typed.Tok.String() + " " + safeIdentifier(typed.Label.Name)}), nil
2949
3318
  case token.GOTO:
2950
3319
  label := safeIdentifier(typed.Label.Name)
2951
3320
  if ctx.gotoStateLabels[label] {
2952
- return []loweredStmt{
2953
- {text: ctx.gotoStateVar + " = " + strconv.Quote(label)},
2954
- {text: "continue " + ctx.gotoStateLoop},
2955
- }, nil
3321
+ return append(out,
3322
+ loweredStmt{text: ctx.gotoStateVar + " = " + strconv.Quote(label)},
3323
+ loweredStmt{text: "continue " + ctx.gotoStateLoop},
3324
+ ), nil
2956
3325
  }
2957
3326
  if ctx.forwardGotos[label] {
2958
- return []loweredStmt{{text: "break " + label}}, nil
3327
+ return append(out, loweredStmt{text: "break " + label}), nil
2959
3328
  }
2960
3329
  if ctx.gotoLabels[label] {
2961
- return []loweredStmt{{text: "continue " + label}}, nil
3330
+ return append(out, loweredStmt{text: "continue " + label}), nil
2962
3331
  }
2963
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported goto branch to "+label)}
3332
+ return out, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported goto branch to "+label)}
2964
3333
  default:
2965
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported labeled branch")}
3334
+ return out, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported labeled branch")}
2966
3335
  }
2967
3336
  }
2968
3337
  switch typed.Tok {
2969
3338
  case token.BREAK, token.CONTINUE:
2970
3339
  if typed.Tok == token.BREAK && ctx.loopLabel != "" && !ctx.switchBreak {
2971
- return []loweredStmt{{text: "break " + ctx.loopLabel}}, nil
3340
+ return append(out, loweredStmt{text: "break " + ctx.loopLabel}), nil
2972
3341
  }
2973
3342
  if typed.Tok == token.CONTINUE && ctx.loopLabel != "" {
2974
- return []loweredStmt{{text: "continue " + ctx.loopLabel}}, nil
3343
+ return append(out, loweredStmt{text: "continue " + ctx.loopLabel}), nil
2975
3344
  }
2976
3345
  if typed.Tok == token.BREAK && ctx.rangeBranch != nil && ctx.rangeBreak {
2977
- return []loweredStmt{{text: "return false"}}, nil
3346
+ return append(out, loweredStmt{text: "return false"}), nil
2978
3347
  }
2979
3348
  if typed.Tok == token.CONTINUE && ctx.rangeBranch != nil && ctx.rangeContinue {
2980
- return []loweredStmt{{text: "return true"}}, nil
3349
+ return append(out, loweredStmt{text: "return true"}), nil
2981
3350
  }
2982
- return []loweredStmt{{text: typed.Tok.String()}}, nil
3351
+ return append(out, loweredStmt{text: typed.Tok.String()}), nil
2983
3352
  case token.FALLTHROUGH:
2984
- return []loweredStmt{{text: "fallthrough"}}, nil
3353
+ return append(out, loweredStmt{text: "fallthrough"}), nil
2985
3354
  default:
2986
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported branch")}
3355
+ return out, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported branch")}
2987
3356
  }
2988
3357
  case *ast.EmptyStmt:
2989
- return nil, nil
3358
+ return out, nil
2990
3359
  default:
2991
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported statement kind")}
3360
+ return out, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported statement kind")}
2992
3361
  }
2993
3362
  }
2994
3363
 
@@ -3034,113 +3403,122 @@ func (o *LoweringOwner) lowerStmtListAfter(
3034
3403
  ) ([]loweredStmt, []Diagnostic) {
3035
3404
  lowered := make([]loweredStmt, 0, len(stmts))
3036
3405
  var diagnostics []Diagnostic
3037
- gotoSpans := backwardGotoLabelSpans(stmts)
3038
- gotoLabels := make(map[string]bool, len(gotoSpans))
3039
- for label := range gotoSpans {
3040
- gotoLabels[label] = true
3041
- }
3042
- forwardSpans := forwardGotoLabelSpans(stmts, gotoSpans)
3043
- forwardStarts := make(map[int]forwardGotoLabelSpan, len(forwardSpans))
3044
- for label, span := range forwardSpans {
3045
- span.label = label
3046
- group := forwardStarts[span.start]
3047
- if group.forwardLabels == nil {
3048
- group.forwardLabels = make(map[string]bool)
3049
- }
3050
- group.forwardLabels[label] = true
3051
- if group.label == "" || span.labelIdx > group.labelIdx {
3052
- group.label = span.label
3053
- group.start = span.start
3054
- group.labelIdx = span.labelIdx
3055
- }
3056
- forwardStarts[span.start] = group
3406
+ hasGoto := stmtListHasGoto(stmts)
3407
+ var gotoSpans map[string]int
3408
+ var gotoLabels map[string]bool
3409
+ var forwardStarts map[int]forwardGotoLabelSpan
3410
+ if hasGoto {
3411
+ gotoSpans = backwardGotoLabelSpans(stmts)
3412
+ gotoLabels = make(map[string]bool, len(gotoSpans))
3413
+ for label := range gotoSpans {
3414
+ gotoLabels[label] = true
3415
+ }
3416
+ forwardSpans := forwardGotoLabelSpans(stmts, gotoSpans)
3417
+ forwardStarts = make(map[int]forwardGotoLabelSpan, len(forwardSpans))
3418
+ for label, span := range forwardSpans {
3419
+ span.label = label
3420
+ group := forwardStarts[span.start]
3421
+ if group.forwardLabels == nil {
3422
+ group.forwardLabels = make(map[string]bool)
3423
+ }
3424
+ group.forwardLabels[label] = true
3425
+ if group.label == "" || span.labelIdx > group.labelIdx {
3426
+ group.label = span.label
3427
+ group.start = span.start
3428
+ group.labelIdx = span.labelIdx
3429
+ }
3430
+ forwardStarts[span.start] = group
3431
+ }
3057
3432
  }
3058
3433
  for idx := 0; idx < len(stmts); idx++ {
3059
3434
  stmt := stmts[idx]
3060
3435
  startLine := sourceLine(ctx, stmt.Pos())
3061
3436
  leading := leadingStmtLines(ctx, prevEndLine, startLine)
3062
- if cluster, ok := gotoStateClusterAt(stmts, idx); ok {
3063
- clusterLowered, clusterDiagnostics := o.lowerGotoStateCluster(ctx, stmts, cluster, leading)
3064
- diagnostics = append(diagnostics, clusterDiagnostics...)
3065
- lowered = append(lowered, clusterLowered...)
3066
- if endLine := sourceLine(ctx, stmts[cluster.endIdx].End()); endLine != 0 {
3067
- prevEndLine = endLine
3068
- }
3069
- idx = cluster.endIdx
3070
- continue
3071
- }
3072
- if span, ok := leadingGotoBackwardLoopSpan(stmts, idx, gotoSpans); ok {
3073
- loop, loopDiagnostics := o.lowerBackwardGotoLoop(
3074
- ctx,
3075
- gotoLabels,
3076
- span.label,
3077
- span.labelIdx,
3078
- span.endIdx,
3079
- span.forwardLabel,
3080
- stmts,
3081
- leading,
3082
- )
3083
- diagnostics = append(diagnostics, loopDiagnostics...)
3084
- lowered = append(lowered, loop...)
3085
- if endLine := sourceLine(ctx, stmts[span.endIdx].End()); endLine != 0 {
3086
- prevEndLine = endLine
3087
- }
3088
- idx = span.endIdx
3089
- continue
3090
- }
3091
- if span, ok := forwardStarts[idx]; ok {
3092
- bodyStmts := stmts[idx:span.labelIdx]
3093
- body, bodyDiagnostics := o.lowerStmtListAfter(
3094
- ctx.withForwardGotos(span.forwardLabels),
3095
- bodyStmts,
3096
- prevEndLine,
3097
- )
3098
- diagnostics = append(diagnostics, bodyDiagnostics...)
3099
- block := loweredStmt{hasBlock: true, text: span.label + ":", children: body}
3100
- if len(leading) != 0 {
3101
- block.leading = append(leading, block.leading...)
3102
- }
3103
- lowered = append(lowered, block)
3104
- if labeled, ok := stmts[span.labelIdx].(*ast.LabeledStmt); ok {
3105
- labelLowered, labelDiagnostics := o.lowerStmt(ctx, labeled.Stmt)
3106
- diagnostics = append(diagnostics, labelDiagnostics...)
3107
- lowered = append(lowered, labelLowered...)
3108
- if endLine := sourceLine(ctx, labeled.End()); endLine != 0 {
3437
+ if hasGoto {
3438
+ if cluster, ok := gotoStateClusterAt(stmts, idx); ok {
3439
+ clusterLowered, clusterDiagnostics := o.lowerGotoStateCluster(ctx, stmts, cluster, leading)
3440
+ diagnostics = append(diagnostics, clusterDiagnostics...)
3441
+ lowered = append(lowered, clusterLowered...)
3442
+ if endLine := sourceLine(ctx, stmts[cluster.endIdx].End()); endLine != 0 {
3109
3443
  prevEndLine = endLine
3110
3444
  }
3445
+ idx = cluster.endIdx
3446
+ continue
3111
3447
  }
3112
- idx = span.labelIdx
3113
- continue
3114
- }
3115
- if labeled, ok := stmt.(*ast.LabeledStmt); ok {
3116
- label := safeIdentifier(labeled.Label.Name)
3117
- if endIdx, ok := gotoSpans[label]; ok {
3448
+ if span, ok := leadingGotoBackwardLoopSpan(stmts, idx, gotoSpans); ok {
3118
3449
  loop, loopDiagnostics := o.lowerBackwardGotoLoop(
3119
3450
  ctx,
3120
3451
  gotoLabels,
3121
- label,
3122
- idx,
3123
- endIdx,
3124
- "",
3452
+ span.label,
3453
+ span.labelIdx,
3454
+ span.endIdx,
3455
+ span.forwardLabel,
3125
3456
  stmts,
3126
3457
  leading,
3127
3458
  )
3128
3459
  diagnostics = append(diagnostics, loopDiagnostics...)
3129
3460
  lowered = append(lowered, loop...)
3130
- if endLine := sourceLine(ctx, stmts[endIdx].End()); endLine != 0 {
3461
+ if endLine := sourceLine(ctx, stmts[span.endIdx].End()); endLine != 0 {
3131
3462
  prevEndLine = endLine
3132
3463
  }
3133
- idx = endIdx
3464
+ idx = span.endIdx
3465
+ continue
3466
+ }
3467
+ if span, ok := forwardStarts[idx]; ok {
3468
+ bodyStmts := stmts[idx:span.labelIdx]
3469
+ body, bodyDiagnostics := o.lowerStmtListAfter(
3470
+ ctx.withForwardGotos(span.forwardLabels),
3471
+ bodyStmts,
3472
+ prevEndLine,
3473
+ )
3474
+ diagnostics = append(diagnostics, bodyDiagnostics...)
3475
+ block := loweredStmt{hasBlock: true, text: span.label + ":", children: body}
3476
+ if len(leading) != 0 {
3477
+ block.leading = append(leading, block.leading...)
3478
+ }
3479
+ lowered = append(lowered, block)
3480
+ if labeled, ok := stmts[span.labelIdx].(*ast.LabeledStmt); ok {
3481
+ labelLowered, labelDiagnostics := o.lowerStmt(ctx, labeled.Stmt)
3482
+ diagnostics = append(diagnostics, labelDiagnostics...)
3483
+ lowered = append(lowered, labelLowered...)
3484
+ if endLine := sourceLine(ctx, labeled.End()); endLine != 0 {
3485
+ prevEndLine = endLine
3486
+ }
3487
+ }
3488
+ idx = span.labelIdx
3134
3489
  continue
3135
3490
  }
3491
+ if labeled, ok := stmt.(*ast.LabeledStmt); ok {
3492
+ label := safeIdentifier(labeled.Label.Name)
3493
+ if endIdx, ok := gotoSpans[label]; ok {
3494
+ loop, loopDiagnostics := o.lowerBackwardGotoLoop(
3495
+ ctx,
3496
+ gotoLabels,
3497
+ label,
3498
+ idx,
3499
+ endIdx,
3500
+ "",
3501
+ stmts,
3502
+ leading,
3503
+ )
3504
+ diagnostics = append(diagnostics, loopDiagnostics...)
3505
+ lowered = append(lowered, loop...)
3506
+ if endLine := sourceLine(ctx, stmts[endIdx].End()); endLine != 0 {
3507
+ prevEndLine = endLine
3508
+ }
3509
+ idx = endIdx
3510
+ continue
3511
+ }
3512
+ }
3136
3513
  }
3137
3514
  if stmtCtx, nextCtx, ok := o.lowerDeclStatementContext(ctx, stmt); ok {
3138
- stmtLowered, stmtDiagnostics := o.lowerStmt(stmtCtx, stmt)
3515
+ start := len(lowered)
3516
+ var stmtDiagnostics []Diagnostic
3517
+ lowered, stmtDiagnostics = o.lowerStmtInto(stmtCtx, stmt, lowered)
3139
3518
  diagnostics = append(diagnostics, stmtDiagnostics...)
3140
- if len(stmtLowered) != 0 && len(leading) != 0 {
3141
- stmtLowered[0].leading = append(leading, stmtLowered[0].leading...)
3519
+ if len(lowered) > start && len(leading) != 0 {
3520
+ lowered[start].leading = append(leading, lowered[start].leading...)
3142
3521
  }
3143
- lowered = append(lowered, stmtLowered...)
3144
3522
  ctx = nextCtx
3145
3523
  if endLine := sourceLine(ctx, stmt.End()); endLine != 0 {
3146
3524
  prevEndLine = endLine
@@ -3165,12 +3543,13 @@ func (o *LoweringOwner) lowerStmtListAfter(
3165
3543
  }
3166
3544
  continue
3167
3545
  }
3168
- stmtLowered, stmtDiagnostics := o.lowerStmt(ctx, stmt)
3546
+ start := len(lowered)
3547
+ var stmtDiagnostics []Diagnostic
3548
+ lowered, stmtDiagnostics = o.lowerStmtInto(ctx, stmt, lowered)
3169
3549
  diagnostics = append(diagnostics, stmtDiagnostics...)
3170
- if len(stmtLowered) != 0 && len(leading) != 0 {
3171
- stmtLowered[0].leading = append(leading, stmtLowered[0].leading...)
3550
+ if len(lowered) > start && len(leading) != 0 {
3551
+ lowered[start].leading = append(leading, lowered[start].leading...)
3172
3552
  }
3173
- lowered = append(lowered, stmtLowered...)
3174
3553
  if endLine := sourceLine(ctx, stmt.End()); endLine != 0 {
3175
3554
  prevEndLine = endLine
3176
3555
  }
@@ -3204,7 +3583,7 @@ func (o *LoweringOwner) lowerDeclStatementContext(
3204
3583
  if def == nil || aliases[def] != "" {
3205
3584
  continue
3206
3585
  }
3207
- if shortDeclDefShadowsOuterName(name.Name, def) {
3586
+ if shortDeclDefShadowsOuterName(ctx, name.Name, def) || valueSpecUsesOuterName(ctx, valueSpec, name.Name, def) {
3208
3587
  aliases[def] = ctx.tempName("Shadow")
3209
3588
  }
3210
3589
  }
@@ -3308,7 +3687,7 @@ func (o *LoweringOwner) lowerGotoStateCluster(
3308
3687
  for _, label := range cluster.labels {
3309
3688
  labels[label.name] = true
3310
3689
  }
3311
- stateCtx := ctx.withGotoState(labels, stateVar, loopLabel)
3690
+ stateCtx := ctx.withGotoState(labels, stateVar, loopLabel).withFunctionScopedDecls()
3312
3691
 
3313
3692
  var diagnostics []Diagnostic
3314
3693
  initialState := cluster.labels[0].name
@@ -3404,7 +3783,7 @@ func (o *LoweringOwner) lowerBackwardGotoLoop(
3404
3783
  var lowered []loweredStmt
3405
3784
  var body []loweredStmt
3406
3785
  var diagnostics []Diagnostic
3407
- bodyCtx := ctx.withGotoLabels(gotoLabels)
3786
+ bodyCtx := ctx.withGotoLabels(gotoLabels).withFunctionScopedDecls()
3408
3787
  if initialForwardLabel != "" {
3409
3788
  skipVar := ctx.tempName("Skip")
3410
3789
  init := loweredStmt{text: "let " + skipVar + " = true"}
@@ -3452,9 +3831,30 @@ type leadingGotoBackwardLoop struct {
3452
3831
  }
3453
3832
 
3454
3833
  func stmtListNeedsLoopBranchLabel(stmts []ast.Stmt) bool {
3834
+ if !stmtListHasGoto(stmts) {
3835
+ return false
3836
+ }
3455
3837
  return len(backwardGotoLabelSpans(stmts)) != 0
3456
3838
  }
3457
3839
 
3840
+ func stmtListHasGoto(stmts []ast.Stmt) bool {
3841
+ for _, stmt := range stmts {
3842
+ hasGoto := false
3843
+ ast.Inspect(stmt, func(node ast.Node) bool {
3844
+ branch, ok := node.(*ast.BranchStmt)
3845
+ if ok && branch.Tok == token.GOTO && branch.Label != nil {
3846
+ hasGoto = true
3847
+ return false
3848
+ }
3849
+ return !hasGoto
3850
+ })
3851
+ if hasGoto {
3852
+ return true
3853
+ }
3854
+ }
3855
+ return false
3856
+ }
3857
+
3458
3858
  func backwardGotoLabelSpans(stmts []ast.Stmt) map[string]int {
3459
3859
  seenLabels := make(map[string]bool)
3460
3860
  spans := make(map[string]int)
@@ -3673,7 +4073,7 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3673
4073
  }
3674
4074
  prefix := ""
3675
4075
  if stmt.Tok == token.DEFINE {
3676
- prefix = "let "
4076
+ prefix = declarationKeyword(ctx)
3677
4077
  if !allShortAssignTargetsNew(ctx, stmt.Lhs) || o.tupleDeclarationNeedsElementStatements(ctx, stmt) {
3678
4078
  return o.lowerTupleReassignmentStmt(ctx, stmt, right, diagnostics)
3679
4079
  }
@@ -3734,26 +4134,18 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3734
4134
  if starTarget && stmt.Tok != token.DEFINE {
3735
4135
  pointer, pointerDiagnostics := o.lowerPointerStorageExpr(ctx, star.X)
3736
4136
  diagnostics = append(diagnostics, pointerDiagnostics...)
3737
- if stmt.Tok == token.AND_NOT_ASSIGN {
3738
- stmts = append(stmts, loweredStmt{text: pointer + " = " + pointer + " & ~(" + right + ")"})
3739
- continue
3740
- }
3741
4137
  if value, ok := integerQuotientAssignExpr(targetType, pointer, right, stmt.Tok); ok {
3742
4138
  stmts = append(stmts, loweredStmt{text: value})
3743
4139
  continue
3744
4140
  }
3745
- stmts = append(stmts, loweredStmt{text: pointer + " " + stmt.Tok.String() + " " + right})
4141
+ stmts = append(stmts, loweredStmt{text: pointer + " = " + lowerCompoundAssignValue(o.runtimeOwner, targetType, pointer, right, stmt.Tok)})
3746
4142
  continue
3747
4143
  }
3748
4144
  if isShortDecl {
3749
4145
  if ident, ok := lhs.(*ast.Ident); ok {
3750
4146
  right = o.lowerDeclaredValue(ctx, ident, right)
3751
4147
  }
3752
- stmts = append(stmts, loweredStmt{text: "let " + left + o.shortDeclTypeAnnotation(ctx, lhs, stmt.Rhs[idx]) + " = " + right})
3753
- continue
3754
- }
3755
- if stmt.Tok == token.AND_NOT_ASSIGN {
3756
- stmts = append(stmts, loweredStmt{text: left + " = " + left + " & ~(" + right + ")"})
4148
+ stmts = append(stmts, loweredStmt{text: declarationKeyword(ctx) + left + o.shortDeclTypeAnnotation(ctx, lhs, stmt.Rhs[idx]) + " = " + right})
3757
4149
  continue
3758
4150
  }
3759
4151
  if helper, ok := wideIntegerAssignHelper(targetType, stmt.Tok); ok {
@@ -3768,6 +4160,10 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3768
4160
  if stmt.Tok == token.DEFINE {
3769
4161
  op = "="
3770
4162
  }
4163
+ if stmt.Tok != token.ASSIGN && stmt.Tok != token.DEFINE {
4164
+ stmts = append(stmts, loweredStmt{text: left + " = " + lowerCompoundAssignValue(o.runtimeOwner, targetType, left, right, stmt.Tok)})
4165
+ continue
4166
+ }
3771
4167
  stmts = append(stmts, loweredStmt{text: left + " " + op + " " + right})
3772
4168
  }
3773
4169
  return stmts, diagnostics
@@ -3810,6 +4206,7 @@ func lowerCompoundAssignValue(
3810
4206
  if value, ok := integerQuotientAssignValueExpr(targetType, left, right, tok); ok {
3811
4207
  return value
3812
4208
  }
4209
+ right = "(" + right + ")"
3813
4210
  switch tok {
3814
4211
  case token.ADD_ASSIGN:
3815
4212
  return left + " + " + right
@@ -3830,6 +4227,9 @@ func lowerCompoundAssignValue(
3830
4227
  case token.SHL_ASSIGN:
3831
4228
  return left + " << " + right
3832
4229
  case token.SHR_ASSIGN:
4230
+ if bits, ok := unsignedIntegerBits(targetType); ok && bits <= 32 {
4231
+ return "(" + left + " >>> " + right + ") >>> 0"
4232
+ }
3833
4233
  return left + " >> " + right
3834
4234
  case token.AND_NOT_ASSIGN:
3835
4235
  return left + " & ~(" + right + ")"
@@ -3866,30 +4266,31 @@ func integerQuotientAssignValueExpr(targetType types.Type, left string, right st
3866
4266
  }
3867
4267
 
3868
4268
  func wideIntegerAssignHelper(targetType types.Type, tok token.Token) (RuntimeHelper, bool) {
3869
- if !isFixedWideIntegerType(targetType) {
4269
+ if !isRuntimeWideIntegerType(targetType) {
3870
4270
  return "", false
3871
4271
  }
4272
+ signed := isFixedSignedWideIntegerType(targetType)
3872
4273
  switch tok {
3873
4274
  case token.SHL_ASSIGN:
3874
- return RuntimeHelperUint64Shl, true
4275
+ return wideIntegerHelper(signed, RuntimeHelperUint64Shl, RuntimeHelperInt64Shl), true
3875
4276
  case token.SHR_ASSIGN:
3876
- return RuntimeHelperUint64Shr, true
4277
+ return wideIntegerHelper(signed, RuntimeHelperUint64Shr, RuntimeHelperInt64Shr), true
3877
4278
  case token.MUL_ASSIGN:
3878
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Mul, RuntimeHelperInt64Mul), true
4279
+ return wideIntegerHelper(signed, RuntimeHelperUint64Mul, RuntimeHelperInt64Mul), true
3879
4280
  case token.QUO_ASSIGN:
3880
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Div, RuntimeHelperInt64Div), true
4281
+ return wideIntegerHelper(signed, RuntimeHelperUint64Div, RuntimeHelperInt64Div), true
3881
4282
  case token.REM_ASSIGN:
3882
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Mod, RuntimeHelperInt64Mod), true
4283
+ return wideIntegerHelper(signed, RuntimeHelperUint64Mod, RuntimeHelperInt64Mod), true
3883
4284
  case token.ADD_ASSIGN:
3884
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Add, RuntimeHelperInt64Add), true
4285
+ return wideIntegerHelper(signed, RuntimeHelperUint64Add, RuntimeHelperInt64Add), true
3885
4286
  case token.SUB_ASSIGN:
3886
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Sub, RuntimeHelperInt64Sub), true
4287
+ return wideIntegerHelper(signed, RuntimeHelperUint64Sub, RuntimeHelperInt64Sub), true
3887
4288
  case token.AND_ASSIGN:
3888
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64And, RuntimeHelperInt64And), true
4289
+ return wideIntegerHelper(signed, RuntimeHelperUint64And, RuntimeHelperInt64And), true
3889
4290
  case token.OR_ASSIGN:
3890
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Or, RuntimeHelperInt64Or), true
4291
+ return wideIntegerHelper(signed, RuntimeHelperUint64Or, RuntimeHelperInt64Or), true
3891
4292
  case token.XOR_ASSIGN:
3892
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Xor, RuntimeHelperInt64Xor), true
4293
+ return wideIntegerHelper(signed, RuntimeHelperUint64Xor, RuntimeHelperInt64Xor), true
3893
4294
  default:
3894
4295
  return "", false
3895
4296
  }
@@ -3922,7 +4323,7 @@ func (o *LoweringOwner) lowerChannelReceiveAssignStmt(
3922
4323
  diagnostics = append(diagnostics, leftDiagnostics...)
3923
4324
  prefix := ""
3924
4325
  if stmt.Tok == token.DEFINE {
3925
- prefix = "let "
4326
+ prefix = declarationKeyword(ctx)
3926
4327
  left += o.shortDeclTypeAnnotation(ctx, stmt.Lhs[0], nil)
3927
4328
  value = o.lowerDeclaredValue(ctx, stmt.Lhs[0], value)
3928
4329
  }
@@ -3983,7 +4384,8 @@ func isIdentLikeExpr(expr ast.Expr) bool {
3983
4384
  func shortDeclNeedsTypeAnnotation(typ types.Type) bool {
3984
4385
  switch typed := types.Unalias(typ).Underlying().(type) {
3985
4386
  case *types.Pointer:
3986
- return namedStructType(typed.Elem()) != nil || namedNonStructType(typed.Elem()) != nil
4387
+ _, pointsToArray := types.Unalias(typed.Elem()).Underlying().(*types.Array)
4388
+ return pointsToArray || namedStructType(typed.Elem()) != nil || namedNonStructType(typed.Elem()) != nil
3987
4389
  case *types.Map:
3988
4390
  return true
3989
4391
  case *types.Slice:
@@ -4025,7 +4427,7 @@ func (o *LoweringOwner) lowerTupleTargetAssignmentStmt(
4025
4427
  left, diagnostics := o.lowerAssignmentTarget(ctx, lhs, declare)
4026
4428
  prefix := ""
4027
4429
  if declare {
4028
- prefix = "let "
4430
+ prefix = declarationKeyword(ctx)
4029
4431
  left += o.shortDeclTypeAnnotation(ctx, lhs, nil)
4030
4432
  value = o.lowerDeclaredValue(ctx, lhs, value)
4031
4433
  }
@@ -4172,7 +4574,7 @@ func (o *LoweringOwner) lowerShortDeclNewShadowAliases(
4172
4574
  if entry.def == nil || aliases[entry.def] != "" {
4173
4575
  continue
4174
4576
  }
4175
- if shortDeclDefShadowsOuterName(entry.name, entry.def) {
4577
+ if shortDeclDefShadowsOuterName(ctx, entry.name, entry.def) {
4176
4578
  aliases[entry.def] = ctx.tempName("Shadow")
4177
4579
  }
4178
4580
  }
@@ -4201,12 +4603,24 @@ func shortDeclShadowNonValueIdents(ctx lowerFileContext, expr ast.Expr) map[*ast
4201
4603
  return idents
4202
4604
  }
4203
4605
 
4204
- func shortDeclDefShadowsOuterName(name string, def types.Object) bool {
4606
+ func shortDeclDefShadowsOuterName(ctx lowerFileContext, name string, def types.Object) bool {
4205
4607
  for scope := def.Parent(); scope != nil; scope = scope.Parent() {
4206
4608
  if scope == def.Parent() {
4207
4609
  continue
4208
4610
  }
4209
4611
  obj := scope.Lookup(name)
4612
+ if scope.Parent() == types.Universe {
4613
+ if obj == nil {
4614
+ return false
4615
+ }
4616
+ if _, isTypeName := obj.(*types.TypeName); isTypeName {
4617
+ return true
4618
+ }
4619
+ if _, isFunc := obj.(*types.Func); isFunc {
4620
+ return sameSourceFile(ctx, obj.Pos(), def.Pos()) && obj.Pos() < def.Pos()
4621
+ }
4622
+ return false
4623
+ }
4210
4624
  if obj != nil && obj.Pos().IsValid() && obj.Pos() < def.Pos() {
4211
4625
  return true
4212
4626
  }
@@ -4214,6 +4628,40 @@ func shortDeclDefShadowsOuterName(name string, def types.Object) bool {
4214
4628
  return false
4215
4629
  }
4216
4630
 
4631
+ func sameSourceFile(ctx lowerFileContext, left token.Pos, right token.Pos) bool {
4632
+ if !left.IsValid() || !right.IsValid() || ctx.semPkg == nil || ctx.semPkg.source == nil {
4633
+ return false
4634
+ }
4635
+ leftPos := sourcePos(ctx.semPkg.source, left)
4636
+ rightPos := sourcePos(ctx.semPkg.source, right)
4637
+ return leftPos.file != "" && leftPos.file == rightPos.file
4638
+ }
4639
+
4640
+ func valueSpecUsesOuterName(ctx lowerFileContext, spec *ast.ValueSpec, name string, def types.Object) bool {
4641
+ if spec == nil || name == "" || def == nil {
4642
+ return false
4643
+ }
4644
+ usesOuter := false
4645
+ for _, value := range spec.Values {
4646
+ ast.Inspect(value, func(node ast.Node) bool {
4647
+ ident, ok := node.(*ast.Ident)
4648
+ if !ok || ident.Name != name {
4649
+ return true
4650
+ }
4651
+ obj := ctx.semPkg.source.TypesInfo.Uses[ident]
4652
+ if obj != nil && obj != def {
4653
+ usesOuter = true
4654
+ return false
4655
+ }
4656
+ return true
4657
+ })
4658
+ if usesOuter {
4659
+ return true
4660
+ }
4661
+ }
4662
+ return false
4663
+ }
4664
+
4217
4665
  func (o *LoweringOwner) mapIndexDefaultUsesShortDeclName(
4218
4666
  ctx lowerFileContext,
4219
4667
  rhs ast.Expr,
@@ -5273,7 +5721,7 @@ func (o *LoweringOwner) lowerRangeFuncStmt(
5273
5721
  diagnostics = append(diagnostics, assignmentDiagnostics...)
5274
5722
  body = append(assignments, body...)
5275
5723
  }
5276
- async := ctx.asyncFunction
5724
+ async := ctx.asyncFunction || stmtsContainAwait(body) || o.rangeFunctionValueNeedsAwait(ctx, stmt.X)
5277
5725
 
5278
5726
  return loweredStmt{rangeFunc: &loweredRangeFunc{
5279
5727
  value: rangeValue,
@@ -5902,6 +6350,19 @@ func (o *LoweringOwner) lowerComplexEqualityExpr(ctx lowerFileContext, expr *ast
5902
6350
  return value, true
5903
6351
  }
5904
6352
 
6353
+ func (o *LoweringOwner) lowerStructEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
6354
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
6355
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
6356
+ if !isStructComparableType(leftType) || !isStructComparableType(rightType) {
6357
+ return "", false
6358
+ }
6359
+ value := o.runtimeOwner.QualifiedHelper(RuntimeHelperComparableEqual) + "(" + left + ", " + right + ")"
6360
+ if expr.Op == token.NEQ {
6361
+ value = "!" + value
6362
+ }
6363
+ return value, true
6364
+ }
6365
+
5905
6366
  func (o *LoweringOwner) lowerStringEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
5906
6367
  leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5907
6368
  rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
@@ -6030,6 +6491,9 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
6030
6491
  if value, ok := o.lowerComplexEqualityExpr(ctx, typed, left, right); ok {
6031
6492
  return value, append(leftDiagnostics, rightDiagnostics...)
6032
6493
  }
6494
+ if value, ok := o.lowerStructEqualityExpr(ctx, typed, left, right); ok {
6495
+ return value, append(leftDiagnostics, rightDiagnostics...)
6496
+ }
6033
6497
  if value, ok := o.lowerStringEqualityExpr(ctx, typed, left, right); ok {
6034
6498
  return value, append(leftDiagnostics, rightDiagnostics...)
6035
6499
  }
@@ -6073,6 +6537,10 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
6073
6537
  return lowerPrefixUnaryExpr(typed.Op, value), diagnostics
6074
6538
  }
6075
6539
  if typed.Op == token.XOR {
6540
+ if bits, ok := unsignedIntegerBits(ctx.semPkg.source.TypesInfo.TypeOf(typed)); ok && bits <= 32 {
6541
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
6542
+ "(~" + value + ", " + strconv.Itoa(bits) + ")", diagnostics
6543
+ }
6076
6544
  return "~" + value, diagnostics
6077
6545
  }
6078
6546
  return value, append(diagnostics, loweringUnsupported("expression", ctx.semPkg.pkgPath, "unsupported unary operator"))
@@ -6155,7 +6623,7 @@ func isLegacyOctalLiteral(value string) bool {
6155
6623
  func (o *LoweringOwner) lowerFuncLit(ctx lowerFileContext, lit *ast.FuncLit) (string, bool, []Diagnostic) {
6156
6624
  signature, _ := ctx.semPkg.source.TypesInfo.TypeOf(lit).(*types.Signature)
6157
6625
  deferState := &loweredDeferState{}
6158
- bodyCtx := ctx.withSignature(signature).withDeferState(deferState).withoutRangeBranch()
6626
+ bodyCtx := ctx.withSignature(signature).withAsyncFunction(false).withDeferState(deferState).withoutRangeBranch()
6159
6627
  asyncCompatibleParams := funcLiteralNeedsAsyncFunctionParamCalls(signature)
6160
6628
  if asyncCompatibleParams || funcLiteralUsesFunctionIdentifierCall(ctx, lit) {
6161
6629
  bodyCtx = bodyCtx.withAsyncFunction(true)
@@ -6276,7 +6744,7 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
6276
6744
  }
6277
6745
  return alias
6278
6746
  }
6279
- if constObj, ok := obj.(*types.Const); ok && ctx.localAliases[obj] != "" {
6747
+ if constObj, ok := obj.(*types.Const); ok && !raw {
6280
6748
  if constValue, ok := lowerConstantValue(constObj.Val()); ok {
6281
6749
  return constValue
6282
6750
  }
@@ -6962,6 +7430,8 @@ func (o *LoweringOwner) lowerConversionExpr(
6962
7430
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperRunesToString) + "(" + value + ")", diagnostics
6963
7431
  case isByteSliceType(sourceType):
6964
7432
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperBytesToString) + "(" + value + ")", diagnostics
7433
+ case overrideNamedStringType(ctx, o, sourceType):
7434
+ return "String(" + value + ")", diagnostics
6965
7435
  case isStringType(sourceType):
6966
7436
  return value, diagnostics
6967
7437
  case isNumericType(sourceType):
@@ -7020,13 +7490,15 @@ func (o *LoweringOwner) lowerConversionExpr(
7020
7490
  return renderNamedStructConversion(conversion), diagnostics
7021
7491
  }
7022
7492
  if isNumericType(targetType) {
7023
- if constantValue, ok := lowerRealNumericConstantExpr(ctx, expr.Args[0]); ok {
7493
+ if constantValue, ok := o.lowerNumericConstantExprForTarget(ctx, expr.Args[0], targetType); ok {
7024
7494
  return constantValue, diagnostics
7025
7495
  }
7026
7496
  }
7027
7497
  if named := namedFunctionType(targetType); named != nil {
7498
+ typeName := runtimeNamedTypeName(named)
7028
7499
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedFunction) +
7029
- "(" + value + ", " + strconv.Quote(runtimeNamedTypeName(named)) + ")", diagnostics
7500
+ "(" + value + ", " + strconv.Quote(typeName) + ", " +
7501
+ o.runtimeFunctionTypeInfo(named.Underlying().(*types.Signature), typeName) + ")", diagnostics
7030
7502
  }
7031
7503
  if named := namedNonStructType(targetType); named != nil {
7032
7504
  if _, ok := named.Underlying().(*types.Slice); ok {
@@ -7052,8 +7524,8 @@ func (o *LoweringOwner) lowerConversionExpr(
7052
7524
  }
7053
7525
 
7054
7526
  func (o *LoweringOwner) lowerWideIntegerBinaryExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
7055
- resultWide := isFixedWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr))
7056
- leftWide := isFixedWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
7527
+ resultWide := isRuntimeWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr))
7528
+ leftWide := isRuntimeWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
7057
7529
  if !resultWide && !leftWide {
7058
7530
  return "", false
7059
7531
  }
@@ -7329,6 +7801,12 @@ func (o *LoweringOwner) lowerPointerReceiverMethodCall(
7329
7801
  methodMemberName(selector.Sel.Name) + "(" + strings.Join(args, ", ") + ")"
7330
7802
  return call, diagnostics, true
7331
7803
  }
7804
+ if crossPackageUnexportedNamedType(ctx, receiver) {
7805
+ call := o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
7806
+ "<any>(" + receiverExpr + ")." + methodMemberName(selector.Sel.Name) +
7807
+ "(" + strings.Join(args, ", ") + ")"
7808
+ return call, diagnostics, true
7809
+ }
7332
7810
  callArgs := append([]string{receiverExpr}, args...)
7333
7811
  call := o.namedTypeExpr(ctx, receiver) + ".prototype." + selector.Sel.Name + ".call(" + strings.Join(callArgs, ", ") + ")"
7334
7812
  return call, diagnostics, true
@@ -8492,12 +8970,40 @@ func (o *LoweringOwner) lowerStructCompositeLit(
8492
8970
  func compositeLiteralFieldNeedsPreEval(ctx lowerFileContext, expr ast.Expr) bool {
8493
8971
  switch typed := unwrapParenExpr(expr).(type) {
8494
8972
  case *ast.CallExpr:
8973
+ for _, arg := range typed.Args {
8974
+ if compositeLiteralFieldNeedsPreEval(ctx, arg) {
8975
+ return true
8976
+ }
8977
+ }
8495
8978
  if ident, ok := typed.Fun.(*ast.Ident); ok && isBuiltinCallTarget(ctx, ident) {
8496
8979
  return false
8497
8980
  }
8498
8981
  return typeFromExpr(ctx, typed.Fun) == nil
8499
8982
  case *ast.UnaryExpr:
8500
- return typed.Op == token.ARROW
8983
+ return typed.Op == token.ARROW || compositeLiteralFieldNeedsPreEval(ctx, typed.X)
8984
+ case *ast.BinaryExpr:
8985
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X) ||
8986
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Y)
8987
+ case *ast.IndexExpr:
8988
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X) ||
8989
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Index)
8990
+ case *ast.IndexListExpr:
8991
+ if compositeLiteralFieldNeedsPreEval(ctx, typed.X) {
8992
+ return true
8993
+ }
8994
+ for _, index := range typed.Indices {
8995
+ if compositeLiteralFieldNeedsPreEval(ctx, index) {
8996
+ return true
8997
+ }
8998
+ }
8999
+ return false
9000
+ case *ast.SliceExpr:
9001
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X) ||
9002
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Low) ||
9003
+ compositeLiteralFieldNeedsPreEval(ctx, typed.High) ||
9004
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Max)
9005
+ case *ast.StarExpr:
9006
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X)
8501
9007
  default:
8502
9008
  return false
8503
9009
  }
@@ -8562,6 +9068,9 @@ func (o *LoweringOwner) lowerArrayCompositeLit(
8562
9068
  lit *ast.CompositeLit,
8563
9069
  array *types.Array,
8564
9070
  ) (string, []Diagnostic) {
9071
+ if len(lit.Elts) == 0 && isByteType(array.Elem()) {
9072
+ return "new Uint8Array(" + strconv.FormatInt(array.Len(), 10) + ")", nil
9073
+ }
8565
9074
  values := make([]string, int(array.Len()))
8566
9075
  for idx := range values {
8567
9076
  values[idx] = o.lowerZeroValueExprFor(ctx, array.Elem())
@@ -8715,7 +9224,7 @@ func (o *LoweringOwner) lowerValueForTarget(
8715
9224
  }
8716
9225
  }
8717
9226
  if isNumericType(targetType) {
8718
- if constantValue, ok := lowerRealNumericConstantExpr(ctx, expr); ok {
9227
+ if constantValue, ok := o.lowerNumericConstantExprForTarget(ctx, expr, targetType); ok {
8719
9228
  return constantValue
8720
9229
  }
8721
9230
  }
@@ -8744,6 +9253,28 @@ func lowerRealNumericConstantExpr(ctx lowerFileContext, expr ast.Expr) (string,
8744
9253
  }
8745
9254
  }
8746
9255
 
9256
+ func (o *LoweringOwner) lowerNumericConstantExprForTarget(ctx lowerFileContext, expr ast.Expr, targetType types.Type) (string, bool) {
9257
+ if ctx.semPkg == nil || ctx.semPkg.source == nil {
9258
+ return "", false
9259
+ }
9260
+ tv, ok := ctx.semPkg.source.TypesInfo.Types[expr]
9261
+ if ok && tv.Value != nil {
9262
+ if bits, ok := unsignedIntegerBits(targetType); ok && bits >= 64 {
9263
+ if value, ok := lowerWideIntegerConstantValue(tv.Value); ok {
9264
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) + "(" +
9265
+ strconv.Quote(value) + ", 64)", true
9266
+ }
9267
+ }
9268
+ if bits, ok := signedIntegerBits(targetType); ok && bits >= 64 {
9269
+ if value, ok := lowerWideIntegerConstantValue(tv.Value); ok {
9270
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperInt) + "(" +
9271
+ strconv.Quote(value) + ", 64)", true
9272
+ }
9273
+ }
9274
+ }
9275
+ return lowerRealNumericConstantExpr(ctx, expr)
9276
+ }
9277
+
8747
9278
  func isRealNumericConstantExpr(ctx lowerFileContext, expr ast.Expr) bool {
8748
9279
  if ctx.semPkg != nil && ctx.semPkg.source != nil {
8749
9280
  if tv, ok := ctx.semPkg.source.TypesInfo.Types[expr]; ok && tv.Value != nil {
@@ -8789,6 +9320,9 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
8789
9320
  return wrapper
8790
9321
  }
8791
9322
  }
9323
+ if wrapper := o.lowerNumericInterfaceWrapper(ctx, targetType, sourceType, value); wrapper != "" {
9324
+ return wrapper
9325
+ }
8792
9326
  if isInterfaceType(targetType) && isStructValueType(sourceType) {
8793
9327
  if cloneStructValue {
8794
9328
  value = o.lowerStructClone(value)
@@ -8837,6 +9371,25 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
8837
9371
  return value
8838
9372
  }
8839
9373
 
9374
+ func (o *LoweringOwner) lowerNumericInterfaceWrapper(
9375
+ ctx lowerFileContext,
9376
+ targetType types.Type,
9377
+ sourceType types.Type,
9378
+ value string,
9379
+ ) string {
9380
+ if targetType == nil || sourceType == nil || !isInterfaceType(targetType) || isInterfaceType(sourceType) {
9381
+ return ""
9382
+ }
9383
+ basic, ok := types.Unalias(sourceType).(*types.Basic)
9384
+ if !ok || basic.Info()&types.IsNumeric == 0 || basic.Info()&types.IsUntyped != 0 {
9385
+ return ""
9386
+ }
9387
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
9388
+ "<" + o.tsTypeFor(ctx, targetType) + ">(" + value + ", " +
9389
+ strconv.Quote(goRuntimeTypeString(sourceType)) + ", {}, " +
9390
+ o.runtimeTypeInfoExpr(sourceType) + ")"
9391
+ }
9392
+
8840
9393
  func isBasicFixedWideIntegerType(typ types.Type) bool {
8841
9394
  basic, ok := types.Unalias(typ).(*types.Basic)
8842
9395
  if !ok {
@@ -8876,7 +9429,8 @@ func (o *LoweringOwner) lowerNamedValueInterfaceWrapper(
8876
9429
  }
8877
9430
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
8878
9431
  "<" + o.tsTypeFor(ctx, targetType) + ">(" + value + ", " +
8879
- strconv.Quote(goRuntimeTypeString(sourceType)) + ", " + methods + ")"
9432
+ strconv.Quote(goRuntimeTypeString(sourceType)) + ", " + methods + ", " +
9433
+ o.runtimeTypeInfoExpr(sourceType) + ")"
8880
9434
  }
8881
9435
 
8882
9436
  func (o *LoweringOwner) lowerPrimitiveErrorWrapper(ctx lowerFileContext, sourceType types.Type, value string) string {
@@ -8898,7 +9452,8 @@ func (o *LoweringOwner) lowerPrimitiveErrorWrapper(ctx lowerFileContext, sourceT
8898
9452
  }
8899
9453
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
8900
9454
  "<$.GoError>(" + value + ", " + strconv.Quote(goRuntimeTypeString(sourceType)) +
8901
- ", {\"Error\": " + o.methodFunctionExpr(ctx, named, fn, "Error") + "})"
9455
+ ", {\"Error\": " + o.methodFunctionExpr(ctx, named, fn, "Error") + "}, " +
9456
+ o.runtimeTypeInfoExpr(sourceType) + ")"
8902
9457
  }
8903
9458
 
8904
9459
  func (o *LoweringOwner) lowerStructClone(value string) string {
@@ -8955,7 +9510,7 @@ func (o *LoweringOwner) lowerZeroValueExprFor(ctx lowerFileContext, typ types.Ty
8955
9510
 
8956
9511
  func (o *LoweringOwner) lowerDeclarationZeroValueExpr(ctx lowerFileContext, typ types.Type) string {
8957
9512
  if isFunctionType(typ) {
8958
- return "null as " + o.tsTypeFor(ctx, typ)
9513
+ return "null as unknown as " + o.tsFunctionZeroValueTypeFor(ctx, typ)
8959
9514
  }
8960
9515
  typeParam, ok := types.Unalias(typ).(*types.TypeParam)
8961
9516
  if !ok {
@@ -8972,6 +9527,13 @@ func (o *LoweringOwner) lowerDeclarationZeroValueExpr(ctx lowerFileContext, typ
8972
9527
  "(__typeArgs, " + strconv.Quote(typeParam.Obj().Name()) + ", " + zeroValueExpr(typ) + ")"
8973
9528
  }
8974
9529
 
9530
+ func (o *LoweringOwner) tsFunctionZeroValueTypeFor(ctx lowerFileContext, typ types.Type) string {
9531
+ if signature := unnamedSignatureForType(typ); signature != nil {
9532
+ return o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
9533
+ }
9534
+ return o.tsTypeFor(ctx, typ)
9535
+ }
9536
+
8975
9537
  func (o *LoweringOwner) runtimeTypeInfoExpr(typ types.Type) string {
8976
9538
  return o.runtimeTypeInfoExprWithSeen(typ, make(map[types.Type]bool))
8977
9539
  }
@@ -9062,7 +9624,7 @@ func (o *LoweringOwner) shallowRuntimeTypeInfoExpr(typ types.Type) string {
9062
9624
  case *types.Pointer:
9063
9625
  return "{ kind: " + typeKind + ".Pointer, elemType: { kind: " + typeKind + ".Basic, name: \"unknown\" } }"
9064
9626
  case *types.Struct:
9065
- return "{ kind: " + typeKind + ".Struct, methods: [], fields: {} }"
9627
+ return "{ kind: " + typeKind + ".Struct, methods: [], fields: [] }"
9066
9628
  case *types.Slice:
9067
9629
  return "{ kind: " + typeKind + ".Slice, elemType: { kind: " + typeKind + ".Basic, name: \"unknown\" } }"
9068
9630
  case *types.Array:
@@ -9078,6 +9640,11 @@ func (o *LoweringOwner) shallowRuntimeTypeInfoExpr(typ types.Type) string {
9078
9640
 
9079
9641
  func (o *LoweringOwner) runtimeStructFieldsExpr(structType *types.Struct, seen map[types.Type]bool) string {
9080
9642
  fields := make([]string, 0, structType.NumFields())
9643
+ var vars []*types.Var
9644
+ for field := range structType.Fields() {
9645
+ vars = append(vars, field)
9646
+ }
9647
+ offsets := structFieldOffsets(goScriptTypeSizes(), vars)
9081
9648
  for idx := range structType.NumFields() {
9082
9649
  field := structType.Field(idx)
9083
9650
  fieldName := tsStructFieldName(field.Name(), idx)
@@ -9085,30 +9652,71 @@ func (o *LoweringOwner) runtimeStructFieldsExpr(structType *types.Struct, seen m
9085
9652
  if fieldName != field.Name() {
9086
9653
  runtimeName = field.Name()
9087
9654
  }
9655
+ pkgPath := ""
9656
+ if !field.Exported() && field.Pkg() != nil {
9657
+ pkgPath = field.Pkg().Path()
9658
+ }
9088
9659
  fieldInfo := runtimeStructFieldInfoExpr(
9089
9660
  o.runtimeTypeInfoExprWithSeen(field.Type(), seen),
9661
+ fieldName,
9090
9662
  runtimeName,
9091
9663
  structType.Tag(idx),
9664
+ pkgPath,
9665
+ field.Embedded(),
9666
+ []int{idx},
9667
+ offsets[idx],
9668
+ field.Exported(),
9092
9669
  )
9093
- fields = append(fields, strconv.Quote(fieldName)+": "+fieldInfo)
9670
+ fields = append(fields, fieldInfo)
9094
9671
  }
9095
- return "{" + strings.Join(fields, ", ") + "}"
9672
+ return "[" + strings.Join(fields, ", ") + "]"
9096
9673
  }
9097
9674
 
9098
- func runtimeStructFieldInfoExpr(runtimeType string, runtimeName string, tag string) string {
9099
- if runtimeName == "" && tag == "" {
9100
- return runtimeType
9675
+ func runtimeStructFieldInfoExpr(
9676
+ runtimeType string,
9677
+ storageKey string,
9678
+ runtimeName string,
9679
+ tag string,
9680
+ pkgPath string,
9681
+ anonymous bool,
9682
+ index []int,
9683
+ offset int64,
9684
+ exported bool,
9685
+ ) string {
9686
+ name := runtimeName
9687
+ if name == "" {
9688
+ name = storageKey
9689
+ }
9690
+ fields := []string{
9691
+ "name: " + strconv.Quote(name),
9692
+ "key: " + strconv.Quote(storageKey),
9693
+ "type: " + runtimeType,
9101
9694
  }
9102
- fields := []string{"type: " + runtimeType}
9103
9695
  if runtimeName != "" {
9104
- fields = append(fields, "name: "+strconv.Quote(runtimeName))
9696
+ fields = append(fields, "pkgPath: "+strconv.Quote(pkgPath))
9697
+ } else if pkgPath != "" {
9698
+ fields = append(fields, "pkgPath: "+strconv.Quote(pkgPath))
9105
9699
  }
9106
9700
  if tag != "" {
9107
9701
  fields = append(fields, "tag: "+strconv.Quote(tag))
9108
9702
  }
9703
+ if anonymous {
9704
+ fields = append(fields, "anonymous: true")
9705
+ }
9706
+ fields = append(fields, "index: "+runtimeStructFieldIndexExpr(index))
9707
+ fields = append(fields, "offset: "+strconv.FormatInt(offset, 10))
9708
+ fields = append(fields, "exported: "+strconv.FormatBool(exported))
9109
9709
  return "{ " + strings.Join(fields, ", ") + " }"
9110
9710
  }
9111
9711
 
9712
+ func runtimeStructFieldIndexExpr(index []int) string {
9713
+ values := make([]string, 0, len(index))
9714
+ for _, value := range index {
9715
+ values = append(values, strconv.Itoa(value))
9716
+ }
9717
+ return "[" + strings.Join(values, ", ") + "]"
9718
+ }
9719
+
9112
9720
  func (o *LoweringOwner) runtimeFunctionTypeInfo(signature *types.Signature, name string) string {
9113
9721
  return o.runtimeFunctionTypeInfoWithSeen(signature, name, make(map[types.Type]bool))
9114
9722
  }
@@ -9588,6 +10196,11 @@ func namedFunctionType(typ types.Type) *types.Named {
9588
10196
  return named
9589
10197
  }
9590
10198
 
10199
+ func overrideNamedStringType(ctx lowerFileContext, owner *LoweringOwner, typ types.Type) bool {
10200
+ named, _ := types.Unalias(typ).(*types.Named)
10201
+ return named != nil && isStringType(named) && owner.typeUsesOverride(named)
10202
+ }
10203
+
9591
10204
  func isBuiltinErrorType(typ types.Type) bool {
9592
10205
  if typ == nil {
9593
10206
  return false
@@ -9738,6 +10351,16 @@ func isStructValueType(typ types.Type) bool {
9738
10351
  return namedStructType(typ) != nil
9739
10352
  }
9740
10353
 
10354
+ func isStructComparableType(typ types.Type) bool {
10355
+ if typ == nil {
10356
+ return false
10357
+ }
10358
+ if _, ok := types.Unalias(typ).Underlying().(*types.Struct); !ok {
10359
+ return false
10360
+ }
10361
+ return types.Comparable(typ)
10362
+ }
10363
+
9741
10364
  func isPointerToStructType(typ types.Type) bool {
9742
10365
  pointer, ok := types.Unalias(typ).Underlying().(*types.Pointer)
9743
10366
  if !ok {
@@ -9917,6 +10540,14 @@ func isFixedSignedWideIntegerType(typ types.Type) bool {
9917
10540
  return ok && basic.Kind() == types.Int64
9918
10541
  }
9919
10542
 
10543
+ func isRuntimeWideIntegerType(typ types.Type) bool {
10544
+ if isFixedWideIntegerType(typ) {
10545
+ return true
10546
+ }
10547
+ bits, ok := unsignedIntegerBits(typ)
10548
+ return ok && bits > 32
10549
+ }
10550
+
9920
10551
  func isRuneSliceType(typ types.Type) bool {
9921
10552
  slice, ok := types.Unalias(typ).Underlying().(*types.Slice)
9922
10553
  return ok && isRuneType(slice.Elem())
@@ -10002,8 +10633,7 @@ func (o *LoweringOwner) functionAsync(ctx lowerFileContext, fn *types.Func) bool
10002
10633
  if fn == nil || ctx.model == nil {
10003
10634
  return false
10004
10635
  }
10005
- semFn := semanticFunctionFor(ctx.model, fn)
10006
- return semFn != nil && semFn.async
10636
+ return ctx.model.functionAsync(fn)
10007
10637
  }
10008
10638
 
10009
10639
  func (o *LoweringOwner) callNeedsAwait(ctx lowerFileContext, fun ast.Expr) bool {
@@ -10152,6 +10782,18 @@ func (o *LoweringOwner) inferGenericTypeArg(
10152
10782
  }
10153
10783
  return
10154
10784
  }
10785
+ if paramNamed, ok := types.Unalias(paramType).(*types.Named); ok {
10786
+ if argNamed, ok := types.Unalias(argType).(*types.Named); ok &&
10787
+ namedOriginsEqual(paramNamed, argNamed) {
10788
+ paramArgs := paramNamed.TypeArgs()
10789
+ argArgs := argNamed.TypeArgs()
10790
+ if paramArgs != nil && argArgs != nil {
10791
+ for idx := range min(paramArgs.Len(), argArgs.Len()) {
10792
+ o.inferGenericTypeArg(inferred, paramArgs.At(idx), argArgs.At(idx))
10793
+ }
10794
+ }
10795
+ }
10796
+ }
10155
10797
  switch param := types.Unalias(paramType).Underlying().(type) {
10156
10798
  case *types.Slice:
10157
10799
  if arg, ok := types.Unalias(argType).Underlying().(*types.Slice); ok {
@@ -10164,6 +10806,24 @@ func (o *LoweringOwner) inferGenericTypeArg(
10164
10806
  }
10165
10807
  }
10166
10808
 
10809
+ func namedOriginsEqual(a, b *types.Named) bool {
10810
+ if a == nil || b == nil {
10811
+ return false
10812
+ }
10813
+ aOrigin := a.Origin()
10814
+ if aOrigin == nil {
10815
+ aOrigin = a
10816
+ }
10817
+ bOrigin := b.Origin()
10818
+ if bOrigin == nil {
10819
+ bOrigin = b
10820
+ }
10821
+ if aOrigin.Obj() == nil || bOrigin.Obj() == nil {
10822
+ return aOrigin == bOrigin
10823
+ }
10824
+ return aOrigin.Obj() == bOrigin.Obj()
10825
+ }
10826
+
10167
10827
  func (o *LoweringOwner) genericTypeDescriptorExpr(ctx lowerFileContext, typ types.Type) string {
10168
10828
  if typeParam, ok := types.Unalias(typ).(*types.TypeParam); ok && typeParamInScope(ctx, typeParam) {
10169
10829
  return "__typeArgs?.[" + strconv.Quote(typeParam.Obj().Name()) + "] ?? { type: " +
@@ -10175,16 +10835,28 @@ func (o *LoweringOwner) genericTypeDescriptorExpr(ctx lowerFileContext, typ type
10175
10835
  }
10176
10836
  if methods := o.genericMethodDescriptors(ctx, typ); methods != "" {
10177
10837
  parts = append(parts, "methods: "+methods)
10838
+ if signatures := o.genericMethodSignatureDescriptors(typ); signatures != "" &&
10839
+ genericTypeDescriptorNeedsMethodSignatures(typ) {
10840
+ parts = append(parts, "methodSignatures: "+signatures)
10841
+ }
10178
10842
  }
10179
10843
  return "{ " + strings.Join(parts, ", ") + " }"
10180
10844
  }
10181
10845
 
10846
+ func genericTypeDescriptorNeedsMethodSignatures(typ types.Type) bool {
10847
+ named, _ := genericMethodSetDescriptorTarget(typ)
10848
+ if named == nil {
10849
+ return false
10850
+ }
10851
+ return namedStructType(named) == nil && !isInterfaceType(named)
10852
+ }
10853
+
10182
10854
  func (o *LoweringOwner) genericMethodDescriptors(ctx lowerFileContext, typ types.Type) string {
10183
- named, _ := types.Unalias(typ).(*types.Named)
10855
+ named, methodSetType := genericMethodSetDescriptorTarget(typ)
10184
10856
  if named == nil {
10185
10857
  return ""
10186
10858
  }
10187
- return o.genericMethodDescriptorsForType(ctx, named, named)
10859
+ return o.genericMethodDescriptorsForType(ctx, named, methodSetType)
10188
10860
  }
10189
10861
 
10190
10862
  func (o *LoweringOwner) genericMethodDescriptorsForType(
@@ -10225,6 +10897,33 @@ func (o *LoweringOwner) genericMethodDescriptorsForType(
10225
10897
  return "{" + strings.Join(methods, ", ") + "}"
10226
10898
  }
10227
10899
 
10900
+ func (o *LoweringOwner) genericMethodSignatureDescriptors(typ types.Type) string {
10901
+ _, methodSetType := genericMethodSetDescriptorTarget(typ)
10902
+ if methodSetType == nil {
10903
+ return ""
10904
+ }
10905
+ methodSet := types.NewMethodSet(methodSetType)
10906
+ methods := make([]string, 0, methodSet.Len())
10907
+ for method := range methodSet.Methods() {
10908
+ fn, _ := method.Obj().(*types.Func)
10909
+ if fn != nil {
10910
+ methods = append(methods, o.runtimeMethodSignature(fn, make(map[types.Type]bool)))
10911
+ }
10912
+ }
10913
+ if len(methods) == 0 {
10914
+ return ""
10915
+ }
10916
+ return "[" + strings.Join(methods, ", ") + "]"
10917
+ }
10918
+
10919
+ func genericMethodSetDescriptorTarget(typ types.Type) (*types.Named, types.Type) {
10920
+ named, _ := types.Unalias(typ).(*types.Named)
10921
+ if named == nil {
10922
+ return namedNonStructMethodSetType(typ)
10923
+ }
10924
+ return named, named
10925
+ }
10926
+
10228
10927
  func namedNonStructMethodSetType(typ types.Type) (*types.Named, types.Type) {
10229
10928
  if named := namedNonStructType(typ); named != nil {
10230
10929
  return named, named
@@ -10377,6 +11076,32 @@ func basicRuntimeName(basic *types.Basic) string {
10377
11076
  return "bool"
10378
11077
  case types.String:
10379
11078
  return "string"
11079
+ case types.Int:
11080
+ return "int"
11081
+ case types.Int8:
11082
+ return "int8"
11083
+ case types.Int16:
11084
+ return "int16"
11085
+ case types.Int32:
11086
+ return "int32"
11087
+ case types.Int64:
11088
+ return "int64"
11089
+ case types.Uint:
11090
+ return "uint"
11091
+ case types.Uint8:
11092
+ return "uint8"
11093
+ case types.Uint16:
11094
+ return "uint16"
11095
+ case types.Uint32:
11096
+ return "uint32"
11097
+ case types.Uint64:
11098
+ return "uint64"
11099
+ case types.Uintptr:
11100
+ return "uintptr"
11101
+ case types.Float32:
11102
+ return "float32"
11103
+ case types.Float64:
11104
+ return "float64"
10380
11105
  case types.Complex64:
10381
11106
  return "complex64"
10382
11107
  case types.Complex128: