goscript 0.1.4 → 0.2.1

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 (295) hide show
  1. package/README.md +5 -2
  2. package/cmd/go_js_wasm_exec/main.go +201 -0
  3. package/cmd/go_js_wasm_exec/main_test.go +83 -0
  4. package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +7 -0
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/cmd/goscript-wasm/main.go +38 -6
  8. package/compiler/compile-request.go +12 -9
  9. package/compiler/compliance_test.go +0 -1
  10. package/compiler/config.go +2 -0
  11. package/compiler/diagnostic.go +104 -12
  12. package/compiler/diagnostic_test.go +106 -0
  13. package/compiler/gotest/request.go +28 -0
  14. package/compiler/gotest/runner.go +354 -44
  15. package/compiler/gotest/runner_test.go +293 -1
  16. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  17. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  18. package/compiler/index.test.ts +23 -0
  19. package/compiler/lowered-program.go +33 -24
  20. package/compiler/lowering.go +746 -194
  21. package/compiler/lowering_bench_test.go +42 -27
  22. package/compiler/lowering_internal_test.go +18 -0
  23. package/compiler/override-facts.go +15 -0
  24. package/compiler/override-parity-verifier.go +450 -0
  25. package/compiler/override-parity.go +122 -0
  26. package/compiler/override-registry_test.go +559 -0
  27. package/compiler/protobuf-ts-binding.go +567 -0
  28. package/compiler/protobuf-ts-binding_test.go +402 -0
  29. package/compiler/runtime-contract.go +4 -0
  30. package/compiler/runtime-contract_test.go +2 -0
  31. package/compiler/semantic-model-types.go +9 -4
  32. package/compiler/semantic-model.go +282 -70
  33. package/compiler/semantic-model_test.go +82 -1
  34. package/compiler/service.go +21 -1
  35. package/compiler/skeleton_test.go +118 -10
  36. package/compiler/typescript-emitter.go +128 -13
  37. package/compiler/wasm/compile_test.go +37 -4
  38. package/compiler/{wasm_api.go → wasm-api.go} +57 -7
  39. package/dist/gs/builtin/hostio.js +5 -0
  40. package/dist/gs/builtin/hostio.js.map +1 -1
  41. package/dist/gs/builtin/slice.d.ts +13 -2
  42. package/dist/gs/builtin/slice.js +187 -6
  43. package/dist/gs/builtin/slice.js.map +1 -1
  44. package/dist/gs/builtin/type.d.ts +13 -5
  45. package/dist/gs/builtin/type.js +153 -60
  46. package/dist/gs/builtin/type.js.map +1 -1
  47. package/dist/gs/builtin/varRef.d.ts +11 -0
  48. package/dist/gs/builtin/varRef.js +57 -2
  49. package/dist/gs/builtin/varRef.js.map +1 -1
  50. package/dist/gs/bytes/buffer.gs.js +1 -1
  51. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  52. package/dist/gs/bytes/reader.gs.js +1 -1
  53. package/dist/gs/bytes/reader.gs.js.map +1 -1
  54. package/dist/gs/compress/zlib/index.d.ts +10 -3
  55. package/dist/gs/compress/zlib/index.js +50 -16
  56. package/dist/gs/compress/zlib/index.js.map +1 -1
  57. package/dist/gs/encoding/json/index.d.ts +114 -0
  58. package/dist/gs/encoding/json/index.js +544 -36
  59. package/dist/gs/encoding/json/index.js.map +1 -1
  60. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +101 -0
  61. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +589 -0
  62. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  63. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.d.ts +1 -0
  64. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +17 -11
  65. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -1
  66. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  67. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  68. package/dist/gs/go/scanner/index.d.ts +2 -0
  69. package/dist/gs/go/scanner/index.js +29 -5
  70. package/dist/gs/go/scanner/index.js.map +1 -1
  71. package/dist/gs/go/token/index.js +22 -6
  72. package/dist/gs/go/token/index.js.map +1 -1
  73. package/dist/gs/hash/index.d.ts +6 -0
  74. package/dist/gs/hash/index.js +20 -0
  75. package/dist/gs/hash/index.js.map +1 -1
  76. package/dist/gs/internal/byteorder/index.js +2 -2
  77. package/dist/gs/internal/byteorder/index.js.map +1 -1
  78. package/dist/gs/internal/goarch/index.d.ts +43 -3
  79. package/dist/gs/internal/goarch/index.js +42 -10
  80. package/dist/gs/internal/goarch/index.js.map +1 -1
  81. package/dist/gs/io/fs/fs.js +26 -14
  82. package/dist/gs/io/fs/fs.js.map +1 -1
  83. package/dist/gs/io/fs/readdir.js +4 -2
  84. package/dist/gs/io/fs/readdir.js.map +1 -1
  85. package/dist/gs/io/fs/sub.js +8 -1
  86. package/dist/gs/io/fs/sub.js.map +1 -1
  87. package/dist/gs/io/io.d.ts +2 -0
  88. package/dist/gs/io/io.js.map +1 -1
  89. package/dist/gs/math/bits/index.d.ts +5 -0
  90. package/dist/gs/math/bits/index.js +16 -4
  91. package/dist/gs/math/bits/index.js.map +1 -1
  92. package/dist/gs/mime/index.d.ts +16 -0
  93. package/dist/gs/mime/index.js +315 -6
  94. package/dist/gs/mime/index.js.map +1 -1
  95. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  96. package/dist/gs/net/http/httptest/index.js +85 -6
  97. package/dist/gs/net/http/httptest/index.js.map +1 -1
  98. package/dist/gs/net/http/index.d.ts +300 -5
  99. package/dist/gs/net/http/index.js +1598 -58
  100. package/dist/gs/net/http/index.js.map +1 -1
  101. package/dist/gs/os/dir_unix.gs.js +1 -1
  102. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  103. package/dist/gs/os/error.gs.js +1 -1
  104. package/dist/gs/os/error.gs.js.map +1 -1
  105. package/dist/gs/os/exec.gs.d.ts +1 -0
  106. package/dist/gs/os/exec.gs.js +4 -8
  107. package/dist/gs/os/exec.gs.js.map +1 -1
  108. package/dist/gs/os/exec_posix.gs.js +1 -1
  109. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  110. package/dist/gs/os/index.d.ts +1 -1
  111. package/dist/gs/os/index.js +1 -1
  112. package/dist/gs/os/index.js.map +1 -1
  113. package/dist/gs/os/proc.gs.d.ts +4 -0
  114. package/dist/gs/os/proc.gs.js +12 -6
  115. package/dist/gs/os/proc.gs.js.map +1 -1
  116. package/dist/gs/os/root_js.gs.js +1 -1
  117. package/dist/gs/os/root_js.gs.js.map +1 -1
  118. package/dist/gs/os/types.gs.js +1 -1
  119. package/dist/gs/os/types.gs.js.map +1 -1
  120. package/dist/gs/os/types_js.gs.js +1 -1
  121. package/dist/gs/os/types_js.gs.js.map +1 -1
  122. package/dist/gs/os/types_unix.gs.js +1 -1
  123. package/dist/gs/os/types_unix.gs.js.map +1 -1
  124. package/dist/gs/path/path.js +11 -7
  125. package/dist/gs/path/path.js.map +1 -1
  126. package/dist/gs/reflect/index.d.ts +5 -4
  127. package/dist/gs/reflect/index.js +4 -3
  128. package/dist/gs/reflect/index.js.map +1 -1
  129. package/dist/gs/reflect/map.js +15 -0
  130. package/dist/gs/reflect/map.js.map +1 -1
  131. package/dist/gs/reflect/type.d.ts +25 -6
  132. package/dist/gs/reflect/type.js +1475 -228
  133. package/dist/gs/reflect/type.js.map +1 -1
  134. package/dist/gs/reflect/types.d.ts +14 -6
  135. package/dist/gs/reflect/types.js +35 -1
  136. package/dist/gs/reflect/types.js.map +1 -1
  137. package/dist/gs/reflect/value.d.ts +1 -0
  138. package/dist/gs/reflect/value.js +83 -41
  139. package/dist/gs/reflect/value.js.map +1 -1
  140. package/dist/gs/reflect/visiblefields.js +4 -140
  141. package/dist/gs/reflect/visiblefields.js.map +1 -1
  142. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  143. package/dist/gs/runtime/pprof/index.js +50 -30
  144. package/dist/gs/runtime/pprof/index.js.map +1 -1
  145. package/dist/gs/runtime/runtime.js +5 -4
  146. package/dist/gs/runtime/runtime.js.map +1 -1
  147. package/dist/gs/runtime/trace/index.js +5 -19
  148. package/dist/gs/runtime/trace/index.js.map +1 -1
  149. package/dist/gs/strconv/atoi.gs.js +1 -1
  150. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  151. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  152. package/dist/gs/strconv/complex.gs.js +148 -0
  153. package/dist/gs/strconv/complex.gs.js.map +1 -0
  154. package/dist/gs/strconv/index.d.ts +1 -0
  155. package/dist/gs/strconv/index.js +1 -0
  156. package/dist/gs/strconv/index.js.map +1 -1
  157. package/dist/gs/strings/builder.js +1 -1
  158. package/dist/gs/strings/reader.js +9 -5
  159. package/dist/gs/strings/reader.js.map +1 -1
  160. package/dist/gs/strings/replace.js +15 -7
  161. package/dist/gs/strings/replace.js.map +1 -1
  162. package/dist/gs/strings/strings.d.ts +5 -0
  163. package/dist/gs/strings/strings.js +57 -5
  164. package/dist/gs/strings/strings.js.map +1 -1
  165. package/dist/gs/sync/atomic/doc_64.gs.js +7 -6
  166. package/dist/gs/sync/atomic/doc_64.gs.js.map +1 -1
  167. package/dist/gs/sync/atomic/type.gs.js +9 -9
  168. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  169. package/dist/gs/sync/atomic/value.gs.js +2 -2
  170. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  171. package/dist/gs/syscall/env.js +22 -14
  172. package/dist/gs/syscall/env.js.map +1 -1
  173. package/dist/gs/testing/testing.js +55 -13
  174. package/dist/gs/testing/testing.js.map +1 -1
  175. package/dist/gs/time/time.d.ts +24 -1
  176. package/dist/gs/time/time.js +43 -3
  177. package/dist/gs/time/time.js.map +1 -1
  178. package/dist/gs/unique/index.js +7 -1
  179. package/dist/gs/unique/index.js.map +1 -1
  180. package/go.mod +3 -3
  181. package/go.sum +16 -0
  182. package/gs/builtin/hostio.test.ts +16 -0
  183. package/gs/builtin/hostio.ts +7 -0
  184. package/gs/builtin/runtime-contract.test.ts +246 -21
  185. package/gs/builtin/slice.ts +269 -24
  186. package/gs/builtin/type.ts +226 -59
  187. package/gs/builtin/varRef.ts +85 -2
  188. package/gs/bytes/buffer.gs.ts +1 -1
  189. package/gs/bytes/reader.gs.ts +1 -1
  190. package/gs/compress/zlib/index.test.ts +62 -1
  191. package/gs/compress/zlib/index.ts +53 -16
  192. package/gs/compress/zlib/parity.json +51 -0
  193. package/gs/encoding/json/index.test.ts +360 -6
  194. package/gs/encoding/json/index.ts +679 -38
  195. package/gs/encoding/json/parity.json +81 -0
  196. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +373 -3
  197. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +893 -1
  198. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +18 -0
  199. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +17 -11
  200. package/gs/github.com/pkg/errors/errors.ts +54 -30
  201. package/gs/go/scanner/index.test.ts +39 -56
  202. package/gs/go/scanner/index.ts +33 -5
  203. package/gs/go/scanner/parity.json +27 -0
  204. package/gs/go/token/index.ts +22 -6
  205. package/gs/hash/index.test.ts +20 -33
  206. package/gs/hash/index.ts +28 -0
  207. package/gs/hash/parity.json +21 -0
  208. package/gs/internal/byteorder/index.test.ts +2 -2
  209. package/gs/internal/byteorder/index.ts +2 -2
  210. package/gs/internal/goarch/index.test.ts +32 -0
  211. package/gs/internal/goarch/index.ts +45 -13
  212. package/gs/internal/goarch/parity.json +144 -0
  213. package/gs/io/fs/fs.ts +26 -14
  214. package/gs/io/fs/readdir.ts +4 -4
  215. package/gs/io/fs/sub.ts +8 -1
  216. package/gs/io/io.ts +1 -0
  217. package/gs/io/parity.json +162 -0
  218. package/gs/math/bits/index.test.ts +14 -1
  219. package/gs/math/bits/index.ts +23 -4
  220. package/gs/math/bits/parity.json +156 -0
  221. package/gs/mime/index.test.ts +90 -0
  222. package/gs/mime/index.ts +369 -6
  223. package/gs/mime/parity.json +36 -0
  224. package/gs/net/http/httptest/index.test.ts +98 -2
  225. package/gs/net/http/httptest/index.ts +101 -6
  226. package/gs/net/http/httptest/parity.json +15 -0
  227. package/gs/net/http/index.test.ts +781 -12
  228. package/gs/net/http/index.ts +1860 -139
  229. package/gs/net/http/meta.json +16 -1
  230. package/gs/net/http/parity.json +193 -0
  231. package/gs/os/dir_unix.gs.ts +1 -1
  232. package/gs/os/error.gs.ts +1 -1
  233. package/gs/os/exec.gs.ts +4 -8
  234. package/gs/os/exec_posix.gs.ts +1 -1
  235. package/gs/os/index.test.ts +9 -0
  236. package/gs/os/index.ts +1 -0
  237. package/gs/os/parity.json +9 -0
  238. package/gs/os/proc.gs.ts +18 -5
  239. package/gs/os/proc.test.ts +26 -0
  240. package/gs/os/root_js.gs.ts +1 -1
  241. package/gs/os/types.gs.ts +1 -1
  242. package/gs/os/types_js.gs.ts +1 -1
  243. package/gs/os/types_unix.gs.ts +1 -1
  244. package/gs/path/path.ts +11 -7
  245. package/gs/reflect/field.test.ts +37 -15
  246. package/gs/reflect/function-types.test.ts +518 -22
  247. package/gs/reflect/index.ts +8 -6
  248. package/gs/reflect/map.ts +20 -0
  249. package/gs/reflect/meta.json +6 -4
  250. package/gs/reflect/parity.json +234 -0
  251. package/gs/reflect/sliceat.test.ts +156 -0
  252. package/gs/reflect/structof.test.ts +401 -0
  253. package/gs/reflect/type.ts +1961 -317
  254. package/gs/reflect/typefor.test.ts +530 -10
  255. package/gs/reflect/types.ts +43 -18
  256. package/gs/reflect/value.ts +105 -45
  257. package/gs/reflect/visiblefields.ts +5 -168
  258. package/gs/runtime/parity.json +24 -0
  259. package/gs/runtime/pprof/index.test.ts +29 -7
  260. package/gs/runtime/pprof/index.ts +56 -30
  261. package/gs/runtime/pprof/parity.json +27 -0
  262. package/gs/runtime/runtime.test.ts +3 -1
  263. package/gs/runtime/runtime.ts +4 -3
  264. package/gs/runtime/trace/index.test.ts +5 -3
  265. package/gs/runtime/trace/index.ts +8 -20
  266. package/gs/runtime/trace/parity.json +36 -0
  267. package/gs/strconv/atoi.gs.ts +1 -1
  268. package/gs/strconv/complex.gs.ts +174 -0
  269. package/gs/strconv/complex.test.ts +65 -0
  270. package/gs/strconv/index.ts +1 -0
  271. package/gs/strconv/parity.json +120 -0
  272. package/gs/strings/builder.ts +1 -1
  273. package/gs/strings/parity.json +186 -0
  274. package/gs/strings/reader.ts +9 -5
  275. package/gs/strings/replace.ts +15 -7
  276. package/gs/strings/strings.test.ts +22 -2
  277. package/gs/strings/strings.ts +64 -6
  278. package/gs/sync/atomic/doc_64.gs.ts +6 -7
  279. package/gs/sync/atomic/doc_64.test.ts +43 -0
  280. package/gs/sync/atomic/type.gs.ts +9 -9
  281. package/gs/sync/atomic/value.gs.ts +2 -2
  282. package/gs/syscall/env.ts +29 -14
  283. package/gs/testing/testing.test.ts +67 -0
  284. package/gs/testing/testing.ts +87 -19
  285. package/gs/time/parity.json +225 -0
  286. package/gs/time/time.test.ts +20 -2
  287. package/gs/time/time.ts +49 -7
  288. package/gs/unique/index.ts +7 -1
  289. package/package.json +4 -2
  290. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  291. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -926
  292. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  293. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -38
  294. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1361
  295. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
@@ -24,6 +24,18 @@ 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
+ // DisplayRoot is the request root used to format source file names in diagnostics.
32
+ DisplayRoot string
33
+ // OutputPath is the TypeScript output root used for generated relative imports.
34
+ OutputPath string
35
+ // ProtobufTypeScriptBinding binds .pb.go files to sibling .pb.ts files.
36
+ ProtobufTypeScriptBinding bool
37
+ }
38
+
27
39
  // NewLoweringOwner creates the lowering owner.
28
40
  func NewLoweringOwner(runtimeOwner *RuntimeContractOwner, overrideOwner *OverrideRegistryOwner) *LoweringOwner {
29
41
  if runtimeOwner == nil {
@@ -39,7 +51,7 @@ func NewLoweringOwner(runtimeOwner *RuntimeContractOwner, overrideOwner *Overrid
39
51
  }
40
52
 
41
53
  // Build converts the semantic model into the compiler IR.
42
- func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*LoweredProgram, []Diagnostic) {
54
+ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel, opts ...LoweringOptions) (*LoweredProgram, []Diagnostic) {
43
55
  if err := ctx.Err(); err != nil {
44
56
  return nil, []Diagnostic{{
45
57
  Severity: DiagnosticSeverityError,
@@ -55,7 +67,14 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*Lower
55
67
  }}
56
68
  }
57
69
 
70
+ var options LoweringOptions
71
+ if len(opts) != 0 {
72
+ options = opts[0]
73
+ }
74
+
58
75
  program := &LoweredProgram{}
76
+ lazyPackageVars := make(map[string]map[types.Object]bool, len(model.packages))
77
+ runtimeMethodSets := make(runtimeMethodSetCache)
59
78
  semPkgs := make([]*semanticPackage, 0, len(model.packages))
60
79
  for _, semPkg := range model.packages {
61
80
  semPkgs = append(semPkgs, semPkg)
@@ -70,7 +89,7 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*Lower
70
89
  diagnostics = append(diagnostics, loweringUnsupported("package", semPkg.pkgPath, "missing semantic source package"))
71
90
  continue
72
91
  }
73
- loweredPkg, pkgDiagnostics := o.lowerPackage(model, semPkg)
92
+ loweredPkg, pkgDiagnostics := o.lowerPackage(model, semPkg, lazyPackageVars, runtimeMethodSets, options)
74
93
  diagnostics = append(diagnostics, pkgDiagnostics...)
75
94
  if loweredPkg != nil {
76
95
  program.packages = append(program.packages, loweredPkg)
@@ -82,18 +101,70 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*Lower
82
101
  return program, nil
83
102
  }
84
103
 
85
- func (o *LoweringOwner) lowerPackage(model *SemanticModel, semPkg *semanticPackage) (*loweredPackage, []Diagnostic) {
104
+ func (o *LoweringOwner) lowerPackage(
105
+ model *SemanticModel,
106
+ semPkg *semanticPackage,
107
+ lazyPackageVarsByPkg map[string]map[types.Object]bool,
108
+ runtimeMethodSets runtimeMethodSetCache,
109
+ options LoweringOptions,
110
+ ) (*loweredPackage, []Diagnostic) {
86
111
  loweredPkg := &loweredPackage{
87
112
  pkgPath: semPkg.pkgPath,
88
113
  name: semPkg.name,
89
114
  }
90
115
  declFiles := packageDeclFiles(semPkg)
91
116
  outputNames := packageOutputNames(semPkg)
92
- lazyPackageVars := o.lazyPackageVars(semPkg, declFiles)
93
- var diagnostics []Diagnostic
117
+ protobufBindings, bindingDiagnostics := protobufTypeScriptBindings(semPkg, options)
118
+ for sourcePath, binding := range protobufBindings {
119
+ outputNames[sourcePath] = binding.outputName
120
+ }
121
+ lazyPackageVars := o.packageLazyVars(semPkg, lazyPackageVarsByPkg, declFiles)
122
+ diagnostics := append([]Diagnostic(nil), bindingDiagnostics...)
94
123
  for idx, file := range semPkg.source.Syntax {
95
124
  sourcePath := sourceFilePath(semPkg, idx, file)
96
- loweredFile, fileDiagnostics := o.lowerFile(model, semPkg, file, sourcePath, declFiles, outputNames, lazyPackageVars)
125
+ if options.ProtobufTypeScriptBinding && protobufSRPCHasGoScriptReplacement(sourcePath) {
126
+ stub, stubDiagnostics := lowerProtobufSRPCTypeScriptBindingStub(semPkg, sourcePath, options)
127
+ diagnostics = append(diagnostics, stubDiagnostics...)
128
+ if stub != nil {
129
+ loweredPkg.files = append(loweredPkg.files, stub)
130
+ }
131
+ continue
132
+ }
133
+ if binding, ok := protobufBindings[sourcePath]; ok {
134
+ protobufAdapter := !binding.hasOneof && !strings.HasSuffix(filepath.Base(binding.sourcePath), "_srpc.pb.go")
135
+ loweredFile, fileDiagnostics := o.lowerFile(
136
+ model,
137
+ semPkg,
138
+ file,
139
+ sourcePath,
140
+ declFiles,
141
+ outputNames,
142
+ lazyPackageVars,
143
+ lazyPackageVarsByPkg,
144
+ runtimeMethodSets,
145
+ protobufAdapter,
146
+ options.DisplayRoot,
147
+ )
148
+ diagnostics = append(diagnostics, fileDiagnostics...)
149
+ rewriteProtobufTypeScriptBindingFile(loweredFile, binding)
150
+ if loweredFile != nil {
151
+ loweredPkg.files = append(loweredPkg.files, loweredFile)
152
+ }
153
+ continue
154
+ }
155
+ loweredFile, fileDiagnostics := o.lowerFile(
156
+ model,
157
+ semPkg,
158
+ file,
159
+ sourcePath,
160
+ declFiles,
161
+ outputNames,
162
+ lazyPackageVars,
163
+ lazyPackageVarsByPkg,
164
+ runtimeMethodSets,
165
+ false,
166
+ options.DisplayRoot,
167
+ )
97
168
  diagnostics = append(diagnostics, fileDiagnostics...)
98
169
  if loweredFile != nil {
99
170
  loweredPkg.files = append(loweredPkg.files, loweredFile)
@@ -125,6 +196,10 @@ func (o *LoweringOwner) lowerFile(
125
196
  declFiles map[types.Object]string,
126
197
  outputNames map[string]string,
127
198
  lazyPackageVars map[types.Object]bool,
199
+ lazyPackageVarsByPkg map[string]map[types.Object]bool,
200
+ runtimeMethodSets runtimeMethodSetCache,
201
+ protobufTypeScriptAdapter bool,
202
+ displayRoot string,
128
203
  ) (*loweredFile, []Diagnostic) {
129
204
  associatedMethods := o.methodDeclsForFileTypes(semPkg, file)
130
205
  relevantImportFiles := map[string]bool{sourcePath: true}
@@ -146,7 +221,7 @@ func (o *LoweringOwner) lowerFile(
146
221
  importPaths := make(map[string]string)
147
222
  importNames := make(map[string]string)
148
223
  importObjects := make(map[*types.PkgName]string)
149
- localRefs := o.analyzeLocalFileReferences(semPkg, file, sourcePath, associatedMethods, declFiles, outputNames)
224
+ localRefs := o.analyzeLocalFileReferences(semPkg, file, sourcePath, associatedMethods, declFiles, outputNames, runtimeMethodSets)
150
225
  reservedImportAliases := localRefs.reservedNames
151
226
  seenImport := make(map[string]bool)
152
227
  for idx, importFile := range semPkg.source.Syntax {
@@ -231,18 +306,21 @@ func (o *LoweringOwner) lowerFile(
231
306
  loweredFile.imports = append(loweredFile.imports, localImports...)
232
307
 
233
308
  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,
309
+ model: model,
310
+ semPkg: semPkg,
311
+ file: file,
312
+ importAliases: importAliases,
313
+ importPaths: importPaths,
314
+ importNames: importNames,
315
+ importObjects: importObjects,
316
+ sourcePath: sourcePath,
317
+ localAliases: localRefs.aliases,
318
+ lazyPackageVars: lazyPackageVars,
319
+ lazyPackageVarsByPkg: lazyPackageVarsByPkg,
320
+ tempNames: newTempNameOwner(),
321
+ topLevel: true,
322
+ protobufTSAdapter: protobufTypeScriptAdapter,
323
+ displayRoot: displayRoot,
246
324
  }
247
325
  var diagnostics []Diagnostic
248
326
  var packageInitCalls []string
@@ -451,6 +529,24 @@ type localFileReferenceAnalysis struct {
451
529
  implicitRuntime map[string]bool
452
530
  }
453
531
 
532
+ type runtimeMethodSetCache map[*types.Named][]types.Object
533
+
534
+ func (c runtimeMethodSetCache) methods(named *types.Named) []types.Object {
535
+ if named == nil {
536
+ return nil
537
+ }
538
+ if methods, ok := c[named]; ok {
539
+ return methods
540
+ }
541
+ methodSet := types.NewMethodSet(types.NewPointer(named))
542
+ methods := make([]types.Object, 0, methodSet.Len())
543
+ for method := range methodSet.Methods() {
544
+ methods = append(methods, method.Obj())
545
+ }
546
+ c[named] = methods
547
+ return methods
548
+ }
549
+
454
550
  func (o *LoweringOwner) analyzeLocalFileReferences(
455
551
  semPkg *semanticPackage,
456
552
  file *ast.File,
@@ -458,6 +554,7 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
458
554
  associatedMethods []*ast.FuncDecl,
459
555
  declFiles map[types.Object]string,
460
556
  outputNames map[string]string,
557
+ runtimeMethodSets runtimeMethodSetCache,
461
558
  ) localFileReferenceAnalysis {
462
559
  analysis := localFileReferenceAnalysis{
463
560
  reservedNames: make(map[string]bool),
@@ -469,6 +566,8 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
469
566
  }
470
567
  seenObjects := make(map[types.Object]bool)
471
568
  seenTypes := make(map[types.Type]bool)
569
+ seenRuntimeTypes := make(map[types.Type]bool)
570
+ seenRuntimeOwnerTypes := make(map[types.Type]bool)
472
571
  var addTypeDeps func(typ types.Type)
473
572
  var addRuntimeTypeDeps func(typ types.Type)
474
573
  var addRuntimeTypeOwnerDeps func(typ types.Type)
@@ -636,6 +735,10 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
636
735
  if typ == nil {
637
736
  return
638
737
  }
738
+ if seenRuntimeTypes[typ] {
739
+ return
740
+ }
741
+ seenRuntimeTypes[typ] = true
639
742
  if alias, ok := typ.(*types.Alias); ok {
640
743
  addObject(alias.Obj(), true)
641
744
  if args := alias.TypeArgs(); args != nil {
@@ -651,9 +754,8 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
651
754
  for method := range named.Methods() {
652
755
  addObject(method, true)
653
756
  }
654
- methodSet := types.NewMethodSet(types.NewPointer(named))
655
- for method := range methodSet.Methods() {
656
- addObject(method.Obj(), true)
757
+ for _, method := range runtimeMethodSets.methods(named) {
758
+ addObject(method, true)
657
759
  }
658
760
  if args := named.TypeArgs(); args != nil {
659
761
  for t := range args.Types() {
@@ -680,6 +782,10 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
680
782
  if typ == nil {
681
783
  return
682
784
  }
785
+ if seenRuntimeOwnerTypes[typ] {
786
+ return
787
+ }
788
+ seenRuntimeOwnerTypes[typ] = true
683
789
  if alias, ok := typ.(*types.Alias); ok {
684
790
  addObject(alias.Obj(), true)
685
791
  if args := alias.TypeArgs(); args != nil {
@@ -773,6 +879,9 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
773
879
  }
774
880
  ast.Inspect(file, inspect)
775
881
  for _, methodDecl := range associatedMethods {
882
+ if sourcePos(semPkg.source, methodDecl.Pos()).file == sourcePath {
883
+ continue
884
+ }
776
885
  ast.Inspect(methodDecl, inspect)
777
886
  }
778
887
  return analysis
@@ -984,36 +1093,61 @@ func safeParamName(param *types.Var, idx int) string {
984
1093
  }
985
1094
 
986
1095
  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
1096
+ model *SemanticModel
1097
+ semPkg *semanticPackage
1098
+ file *ast.File
1099
+ importAliases map[string]string
1100
+ importPaths map[string]string
1101
+ importNames map[string]string
1102
+ importObjects map[*types.PkgName]string
1103
+ sourcePath string
1104
+ localAliases map[types.Object]string
1105
+ lazyPackageVars map[types.Object]bool
1106
+ lazyPackageVarsByPkg map[string]map[types.Object]bool
1107
+ identAliases map[types.Object]string
1108
+ identAliasRefs map[types.Object]bool
1109
+ tempNames *tempNameOwner
1110
+ signature *types.Signature
1111
+ typeParams map[string]bool
1112
+ staticTypeParams map[string]bool
1113
+ asyncFunction bool
1114
+ functionTypeDepth int
1115
+ deferState *loweredDeferState
1116
+ rangeBranch *loweredRangeBranch
1117
+ rangeBreak bool
1118
+ rangeContinue bool
1119
+ gotoLabels map[string]bool
1120
+ forwardGotos map[string]bool
1121
+ gotoStateLabels map[string]bool
1122
+ gotoStateVar string
1123
+ gotoStateLoop string
1124
+ functionScopedDecls bool
1125
+ loopLabel string
1126
+ switchBreak bool
1127
+ topLevel bool
1128
+ protobufTSAdapter bool
1129
+ displayRoot string
1130
+ }
1131
+
1132
+ func (ctx lowerFileContext) diagnosticPosition(pos token.Pos) *DiagnosticPosition {
1133
+ if ctx.semPkg == nil {
1134
+ return nil
1135
+ }
1136
+ return diagnosticPositionFromSource(sourcePos(ctx.semPkg.source, pos), ctx.displayRoot)
1137
+ }
1138
+
1139
+ func loweringUnsupportedAt(ctx lowerFileContext, node ast.Node, kind string, subject string, detail string) Diagnostic {
1140
+ diag := loweringUnsupported(kind, subject, detail)
1141
+ if node != nil {
1142
+ diag.Position = ctx.diagnosticPosition(node.Pos())
1143
+ }
1144
+ return diag
1145
+ }
1146
+
1147
+ func loweringUnsupportedPos(ctx lowerFileContext, pos token.Pos, kind string, subject string, detail string) Diagnostic {
1148
+ diag := loweringUnsupported(kind, subject, detail)
1149
+ diag.Position = ctx.diagnosticPosition(pos)
1150
+ return diag
1017
1151
  }
1018
1152
 
1019
1153
  type tempNameOwner struct {
@@ -1102,7 +1236,7 @@ func (o *LoweringOwner) lowerDecl(ctx lowerFileContext, decl ast.Decl) ([]lowere
1102
1236
  if receiver := receiverNamedTypeFromDecl(ctx, typed); receiver != nil && namedStructType(receiver) == nil {
1103
1237
  fn, diagnostics := o.lowerNamedReceiverMethodDecl(ctx, typed, receiver)
1104
1238
  if fn == nil {
1105
- return nil, []Diagnostic{loweringUnsupported("function", typed.Name.Name, "missing type information")}
1239
+ return nil, []Diagnostic{loweringUnsupportedAt(ctx, typed, "function", typed.Name.Name, "missing type information")}
1106
1240
  }
1107
1241
  return []loweredDecl{{function: fn}}, diagnostics
1108
1242
  }
@@ -1110,11 +1244,11 @@ func (o *LoweringOwner) lowerDecl(ctx lowerFileContext, decl ast.Decl) ([]lowere
1110
1244
  }
1111
1245
  fn, diagnostics := o.lowerFuncDecl(ctx, typed)
1112
1246
  if fn == nil {
1113
- return nil, []Diagnostic{loweringUnsupported("function", typed.Name.Name, "missing type information")}
1247
+ return nil, []Diagnostic{loweringUnsupportedAt(ctx, typed, "function", typed.Name.Name, "missing type information")}
1114
1248
  }
1115
1249
  return []loweredDecl{{function: fn}}, diagnostics
1116
1250
  default:
1117
- return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported declaration kind")}
1251
+ return nil, []Diagnostic{loweringUnsupportedAt(ctx, decl, "declaration", ctx.semPkg.pkgPath, "unsupported declaration kind")}
1118
1252
  }
1119
1253
  }
1120
1254
 
@@ -1162,7 +1296,7 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
1162
1296
  value = o.lowerValueForTarget(ctx, typed.Values[idx], obj.Type(), lowered)
1163
1297
  value = o.lowerTopLevelInitializerValue(ctx, typed.Values[idx], value)
1164
1298
  } else if len(embedPatterns) != 0 {
1165
- embedded, embedDiagnostics := o.lowerGoEmbedValue(ctx, obj.Type(), embedPatterns)
1299
+ embedded, embedDiagnostics := o.lowerGoEmbedValue(ctx, typed.Pos(), obj.Type(), embedPatterns)
1166
1300
  diagnostics = append(diagnostics, embedDiagnostics...)
1167
1301
  if embedded != "" {
1168
1302
  value = embedded
@@ -1171,7 +1305,7 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
1171
1305
  if _, ok := obj.(*types.Const); !ok && ctx.model.needsVarRef[obj] {
1172
1306
  value = o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(" + value + ")"
1173
1307
  }
1174
- keyword := "let"
1308
+ keyword := strings.TrimSpace(declarationKeyword(ctx))
1175
1309
  if _, ok := obj.(*types.Const); ok || decl.Tok == token.CONST {
1176
1310
  keyword = "const"
1177
1311
  }
@@ -1253,7 +1387,7 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
1253
1387
  }
1254
1388
  }
1255
1389
  default:
1256
- diagnostics = append(diagnostics, loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported general declaration"))
1390
+ diagnostics = append(diagnostics, loweringUnsupportedAt(ctx, typed, "declaration", ctx.semPkg.pkgPath, "unsupported general declaration"))
1257
1391
  }
1258
1392
  }
1259
1393
  return decls, diagnostics
@@ -1402,6 +1536,9 @@ func packageDeclFiles(semPkg *semanticPackage) map[types.Object]string {
1402
1536
  if semPkg == nil || semPkg.source == nil {
1403
1537
  return nil
1404
1538
  }
1539
+ if len(semPkg.source.Syntax) <= 1 {
1540
+ return nil
1541
+ }
1405
1542
  declFiles := make(map[types.Object]string, len(semPkg.declarations))
1406
1543
  for _, decl := range semPkg.declarations {
1407
1544
  if decl.object != nil && decl.position.file != "" {
@@ -1423,6 +1560,31 @@ func packageOutputNames(semPkg *semanticPackage) map[string]string {
1423
1560
  return outputNames
1424
1561
  }
1425
1562
 
1563
+ func (o *LoweringOwner) packageLazyVars(
1564
+ semPkg *semanticPackage,
1565
+ cache map[string]map[types.Object]bool,
1566
+ declFiles map[types.Object]string,
1567
+ ) map[types.Object]bool {
1568
+ if semPkg == nil {
1569
+ return nil
1570
+ }
1571
+ if cache == nil {
1572
+ if declFiles == nil {
1573
+ declFiles = packageDeclFiles(semPkg)
1574
+ }
1575
+ return o.lazyPackageVars(semPkg, declFiles)
1576
+ }
1577
+ if lazy, ok := cache[semPkg.pkgPath]; ok {
1578
+ return lazy
1579
+ }
1580
+ if declFiles == nil {
1581
+ declFiles = packageDeclFiles(semPkg)
1582
+ }
1583
+ lazy := o.lazyPackageVars(semPkg, declFiles)
1584
+ cache[semPkg.pkgPath] = lazy
1585
+ return lazy
1586
+ }
1587
+
1426
1588
  func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage, declFiles map[types.Object]string) map[types.Object]bool {
1427
1589
  if semPkg == nil || semPkg.source == nil {
1428
1590
  return nil
@@ -1589,7 +1751,7 @@ func (o *LoweringOwner) packageVarIsLazy(ctx lowerFileContext, obj *types.Var) b
1589
1751
  if semPkg == nil {
1590
1752
  return false
1591
1753
  }
1592
- for lazyObj := range o.lazyPackageVars(semPkg, packageDeclFiles(semPkg)) {
1754
+ for lazyObj := range o.packageLazyVars(semPkg, ctx.lazyPackageVarsByPkg, nil) {
1593
1755
  if lazyObj != nil && lazyObj.Name() == obj.Name() &&
1594
1756
  lazyObj.Pkg() != nil && lazyObj.Pkg().Path() == obj.Pkg().Path() {
1595
1757
  return true
@@ -1606,7 +1768,7 @@ func (o *LoweringOwner) packageVarNameIsLazy(ctx lowerFileContext, pkgPath, name
1606
1768
  if semPkg == nil {
1607
1769
  return false
1608
1770
  }
1609
- for lazyObj := range o.lazyPackageVars(semPkg, packageDeclFiles(semPkg)) {
1771
+ for lazyObj := range o.packageLazyVars(semPkg, ctx.lazyPackageVarsByPkg, nil) {
1610
1772
  if lazyObj != nil && lazyObj.Name() == name {
1611
1773
  return true
1612
1774
  }
@@ -2010,16 +2172,17 @@ func goEmbedPatterns(groups ...*ast.CommentGroup) []string {
2010
2172
 
2011
2173
  func (o *LoweringOwner) lowerGoEmbedValue(
2012
2174
  ctx lowerFileContext,
2175
+ diagPos token.Pos,
2013
2176
  typ types.Type,
2014
2177
  patterns []string,
2015
2178
  ) (string, []Diagnostic) {
2016
2179
  if isEmbedFSType(typ) {
2017
- return o.lowerGoEmbedFSValue(ctx, patterns)
2180
+ return o.lowerGoEmbedFSValue(ctx, diagPos, patterns)
2018
2181
  }
2019
2182
  if len(patterns) != 1 {
2020
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2183
+ return "", []Diagnostic{loweringUnsupportedPos(ctx, diagPos, "declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2021
2184
  }
2022
- cleanPattern, diagnostics := cleanGoEmbedFilePattern(ctx, patterns[0])
2185
+ cleanPattern, diagnostics := cleanGoEmbedFilePattern(ctx, diagPos, patterns[0])
2023
2186
  if len(diagnostics) != 0 {
2024
2187
  return "", diagnostics
2025
2188
  }
@@ -2033,7 +2196,7 @@ func (o *LoweringOwner) lowerGoEmbedValue(
2033
2196
  if slice, ok := types.Unalias(typ).Underlying().(*types.Slice); ok && isByteType(slice.Elem()) {
2034
2197
  return byteSliceLiteral(data), nil
2035
2198
  }
2036
- diag := loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed target type")
2199
+ diag := loweringUnsupportedPos(ctx, diagPos, "declaration", ctx.semPkg.pkgPath, "unsupported go:embed target type")
2037
2200
  diag.Detail = "target type: " + types.TypeString(typ, func(pkg *types.Package) string {
2038
2201
  if pkg == nil {
2039
2202
  return ""
@@ -2043,18 +2206,18 @@ func (o *LoweringOwner) lowerGoEmbedValue(
2043
2206
  return "", []Diagnostic{diag}
2044
2207
  }
2045
2208
 
2046
- func (o *LoweringOwner) lowerGoEmbedFSValue(ctx lowerFileContext, patterns []string) (string, []Diagnostic) {
2209
+ func (o *LoweringOwner) lowerGoEmbedFSValue(ctx lowerFileContext, diagPos token.Pos, patterns []string) (string, []Diagnostic) {
2047
2210
  embedAlias := ctx.importPaths["embed"]
2048
2211
  if embedAlias == "" {
2049
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed FS import")}
2212
+ return "", []Diagnostic{loweringUnsupportedPos(ctx, diagPos, "declaration", ctx.semPkg.pkgPath, "unsupported go:embed FS import")}
2050
2213
  }
2051
2214
  if len(patterns) == 0 {
2052
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2215
+ return "", []Diagnostic{loweringUnsupportedPos(ctx, diagPos, "declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2053
2216
  }
2054
2217
 
2055
2218
  filesByPath := make(map[string][]byte)
2056
2219
  for _, pattern := range patterns {
2057
- files, diagnostics := expandGoEmbedPattern(ctx, pattern)
2220
+ files, diagnostics := expandGoEmbedPattern(ctx, diagPos, pattern)
2058
2221
  if len(diagnostics) != 0 {
2059
2222
  return "", diagnostics
2060
2223
  }
@@ -2080,25 +2243,25 @@ type goEmbedFile struct {
2080
2243
  data []byte
2081
2244
  }
2082
2245
 
2083
- func cleanGoEmbedFilePattern(ctx lowerFileContext, pattern string) (string, []Diagnostic) {
2084
- cleanPattern, _, diagnostics := cleanGoEmbedPattern(ctx, pattern)
2246
+ func cleanGoEmbedFilePattern(ctx lowerFileContext, diagPos token.Pos, pattern string) (string, []Diagnostic) {
2247
+ cleanPattern, _, diagnostics := cleanGoEmbedPattern(ctx, diagPos, pattern)
2085
2248
  if len(diagnostics) != 0 {
2086
2249
  return "", diagnostics
2087
2250
  }
2088
2251
  if strings.Contains(cleanPattern, "*") {
2089
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2252
+ return "", []Diagnostic{loweringUnsupportedPos(ctx, diagPos, "declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2090
2253
  }
2091
2254
  info, err := os.Stat(filepath.Join(filepath.Dir(ctx.sourcePath), filepath.FromSlash(cleanPattern)))
2092
2255
  if err != nil {
2093
2256
  return "", []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2094
2257
  }
2095
2258
  if info.IsDir() {
2096
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed directory target")}
2259
+ return "", []Diagnostic{loweringUnsupportedPos(ctx, diagPos, "declaration", ctx.semPkg.pkgPath, "unsupported go:embed directory target")}
2097
2260
  }
2098
2261
  return cleanPattern, nil
2099
2262
  }
2100
2263
 
2101
- func cleanGoEmbedPattern(ctx lowerFileContext, pattern string) (string, bool, []Diagnostic) {
2264
+ func cleanGoEmbedPattern(ctx lowerFileContext, diagPos token.Pos, pattern string) (string, bool, []Diagnostic) {
2102
2265
  pattern = strings.Trim(pattern, "`\"")
2103
2266
  all := false
2104
2267
  if strings.HasPrefix(pattern, "all:") {
@@ -2111,13 +2274,13 @@ func cleanGoEmbedPattern(ctx lowerFileContext, pattern string) (string, bool, []
2111
2274
  cleanPattern == "." ||
2112
2275
  cleanPattern == ".." ||
2113
2276
  strings.HasPrefix(cleanPattern, "../") {
2114
- return "", false, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2277
+ return "", false, []Diagnostic{loweringUnsupportedPos(ctx, diagPos, "declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2115
2278
  }
2116
2279
  return cleanPattern, all, nil
2117
2280
  }
2118
2281
 
2119
- func expandGoEmbedPattern(ctx lowerFileContext, pattern string) ([]goEmbedFile, []Diagnostic) {
2120
- cleanPattern, all, diagnostics := cleanGoEmbedPattern(ctx, pattern)
2282
+ func expandGoEmbedPattern(ctx lowerFileContext, diagPos token.Pos, pattern string) ([]goEmbedFile, []Diagnostic) {
2283
+ cleanPattern, all, diagnostics := cleanGoEmbedPattern(ctx, diagPos, pattern)
2121
2284
  if len(diagnostics) != 0 {
2122
2285
  return nil, diagnostics
2123
2286
  }
@@ -2126,17 +2289,17 @@ func expandGoEmbedPattern(ctx lowerFileContext, pattern string) ([]goEmbedFile,
2126
2289
  if strings.Contains(cleanPattern, "*") {
2127
2290
  matches, err := filepath.Glob(filepath.Join(pkgDir, filepath.FromSlash(cleanPattern)))
2128
2291
  if err != nil {
2129
- return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2292
+ return nil, []Diagnostic{loweringUnsupportedPos(ctx, diagPos, "declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2130
2293
  }
2131
2294
  if len(matches) == 0 {
2132
- return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "go:embed pattern matched no files")}
2295
+ return nil, []Diagnostic{loweringUnsupportedPos(ctx, diagPos, "declaration", ctx.semPkg.pkgPath, "go:embed pattern matched no files")}
2133
2296
  }
2134
2297
  paths = matches
2135
2298
  }
2136
2299
 
2137
2300
  var files []goEmbedFile
2138
2301
  for _, path := range paths {
2139
- collected, diagnostics := collectGoEmbedPath(ctx, pkgDir, path, all)
2302
+ collected, diagnostics := collectGoEmbedPath(ctx, diagPos, pkgDir, path, all)
2140
2303
  if len(diagnostics) != 0 {
2141
2304
  return nil, diagnostics
2142
2305
  }
@@ -2148,7 +2311,7 @@ func expandGoEmbedPattern(ctx lowerFileContext, pattern string) ([]goEmbedFile,
2148
2311
  return files, nil
2149
2312
  }
2150
2313
 
2151
- func collectGoEmbedPath(ctx lowerFileContext, pkgDir, absPath string, all bool) ([]goEmbedFile, []Diagnostic) {
2314
+ func collectGoEmbedPath(ctx lowerFileContext, diagPos token.Pos, pkgDir, absPath string, all bool) ([]goEmbedFile, []Diagnostic) {
2152
2315
  info, err := os.Stat(absPath)
2153
2316
  if err != nil {
2154
2317
  return nil, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
@@ -2185,7 +2348,7 @@ func collectGoEmbedPath(ctx lowerFileContext, pkgDir, absPath string, all bool)
2185
2348
  return nil, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2186
2349
  }
2187
2350
  if len(files) == 0 {
2188
- return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "go:embed directory matched no files")}
2351
+ return nil, []Diagnostic{loweringUnsupportedPos(ctx, diagPos, "declaration", ctx.semPkg.pkgPath, "go:embed directory matched no files")}
2189
2352
  }
2190
2353
  return files, nil
2191
2354
  }
@@ -2306,7 +2469,7 @@ func (o *LoweringOwner) lowerInterfaceType(ctx lowerFileContext, semType *semant
2306
2469
  }
2307
2470
  code = code + "\n\n" + o.runtimeOwner.QualifiedHelper(RuntimeHelperRegisterInterfaceType) +
2308
2471
  "(\n\t" + strconv.Quote(runtimeNamedTypeName(semType.named)) +
2309
- ",\n\tnull,\n\t" + o.runtimeMethodSignatures(iface) + "\n)"
2472
+ ",\n\tnull,\n\t" + o.runtimeMethodSignatures(iface) + "\n);"
2310
2473
  return loweredDecl{code: code, typeIndexExport: typeIndexExport, sideEffect: true}
2311
2474
  }
2312
2475
 
@@ -2387,12 +2550,13 @@ func (o *LoweringOwner) runtimeMethodReturns(tuple *types.Tuple, seen map[types.
2387
2550
 
2388
2551
  func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticType) (*loweredStruct, []Diagnostic) {
2389
2552
  lowered := &loweredStruct{
2390
- exported: ctx.topLevel,
2391
- indexExported: ctx.topLevel && ast.IsExported(semType.name),
2392
- name: safeIdentifier(semType.name),
2393
- typeName: runtimeNamedTypeName(semType.named),
2394
- cloneMethod: "clone",
2395
- fields: make([]loweredStructField, 0, len(semType.fields)),
2553
+ exported: ctx.topLevel,
2554
+ indexExported: ctx.topLevel && ast.IsExported(semType.name),
2555
+ protobufPreserveJSON: ctx.protobufTSAdapter && o.protobufTypeScriptAdapterPreserveJSON(ctx, semType, make(map[*types.Named]bool)),
2556
+ name: safeIdentifier(semType.name),
2557
+ typeName: runtimeNamedTypeName(semType.named),
2558
+ cloneMethod: "clone",
2559
+ fields: make([]loweredStructField, 0, len(semType.fields)),
2396
2560
  }
2397
2561
  for idx, field := range semType.fields {
2398
2562
  structValue := isStructValueType(field.typ)
@@ -2412,6 +2576,11 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2412
2576
  runtimeType: o.runtimeTypeInfoExpr(field.typ),
2413
2577
  doc: field.doc,
2414
2578
  tag: field.tag,
2579
+ pkgPath: field.pkgPath,
2580
+ index: field.index,
2581
+ offset: field.offset,
2582
+ anonymous: field.embedded,
2583
+ exported: field.exported,
2415
2584
  structValue: structValue,
2416
2585
  arrayValue: isArrayType(field.typ),
2417
2586
  })
@@ -2429,7 +2598,17 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2429
2598
  }
2430
2599
  var diagnostics []Diagnostic
2431
2600
  for _, methodDecl := range methodDecls {
2432
- method, methodDiagnostics := o.lowerFuncDecl(ctx, methodDecl)
2601
+ lowerDecl := methodDecl
2602
+ methodSourcePath := sourcePos(ctx.semPkg.source, methodDecl.Pos()).file
2603
+ if ctx.protobufTSAdapter &&
2604
+ methodSourcePath == ctx.sourcePath &&
2605
+ protobufTypeScriptBindingReplacesMethodName(methodDecl.Name.Name) &&
2606
+ !(lowered.protobufPreserveJSON && protobufTypeScriptBindingJSONMethodName(methodDecl.Name.Name)) {
2607
+ bodyless := *methodDecl
2608
+ bodyless.Body = nil
2609
+ lowerDecl = &bodyless
2610
+ }
2611
+ method, methodDiagnostics := o.lowerFuncDecl(ctx, lowerDecl)
2433
2612
  diagnostics = append(diagnostics, methodDiagnostics...)
2434
2613
  if method != nil {
2435
2614
  if method.name == "clone" {
@@ -2445,6 +2624,133 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2445
2624
  return lowered, diagnostics
2446
2625
  }
2447
2626
 
2627
+ func (o *LoweringOwner) protobufTypeScriptAdapterPreserveJSON(
2628
+ ctx lowerFileContext,
2629
+ semType *semanticType,
2630
+ seen map[*types.Named]bool,
2631
+ ) bool {
2632
+ if semType == nil || semType.named == nil {
2633
+ return false
2634
+ }
2635
+ named := semType.named.Origin()
2636
+ if named == nil || seen[named] {
2637
+ return false
2638
+ }
2639
+ seen[named] = true
2640
+ for _, methodDecl := range o.methodDeclsForType(ctx, named) {
2641
+ if methodDecl == nil || !protobufTypeScriptBindingJSONMethodName(methodDecl.Name.Name) {
2642
+ continue
2643
+ }
2644
+ if sourcePos(ctx.semPkg.source, methodDecl.Pos()).file != ctx.sourcePath {
2645
+ return true
2646
+ }
2647
+ }
2648
+ for _, field := range semType.fields {
2649
+ if o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, field.typ, seen) {
2650
+ return true
2651
+ }
2652
+ }
2653
+ return false
2654
+ }
2655
+
2656
+ func (o *LoweringOwner) protobufTypeScriptAdapterTypeHasCustomJSON(
2657
+ ctx lowerFileContext,
2658
+ typ types.Type,
2659
+ seen map[*types.Named]bool,
2660
+ ) bool {
2661
+ if typ == nil {
2662
+ return false
2663
+ }
2664
+ if alias, ok := typ.(*types.Alias); ok {
2665
+ if o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, alias.Rhs(), seen) {
2666
+ return true
2667
+ }
2668
+ if args := alias.TypeArgs(); args != nil {
2669
+ for t := range args.Types() {
2670
+ if o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, t, seen) {
2671
+ return true
2672
+ }
2673
+ }
2674
+ }
2675
+ return false
2676
+ }
2677
+ if named, ok := types.Unalias(typ).(*types.Named); ok {
2678
+ if o.protobufTypeScriptAdapterNamedTypeHasCustomJSON(ctx, named) {
2679
+ return true
2680
+ }
2681
+ if obj := named.Obj(); obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == ctx.semPkg.pkgPath {
2682
+ semType := ctx.model.types[named]
2683
+ if semType == nil {
2684
+ semType = ctx.model.types[named.Origin()]
2685
+ }
2686
+ if semType != nil && o.protobufTypeScriptAdapterPreserveJSON(ctx, semType, seen) {
2687
+ return true
2688
+ }
2689
+ }
2690
+ origin := named.Origin()
2691
+ if origin != nil {
2692
+ if seen[origin] {
2693
+ return false
2694
+ }
2695
+ seen[origin] = true
2696
+ }
2697
+ if args := named.TypeArgs(); args != nil {
2698
+ for t := range args.Types() {
2699
+ if o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, t, seen) {
2700
+ return true
2701
+ }
2702
+ }
2703
+ }
2704
+ if o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, named.Underlying(), seen) {
2705
+ return true
2706
+ }
2707
+ }
2708
+ switch typed := types.Unalias(typ).Underlying().(type) {
2709
+ case *types.Pointer:
2710
+ return o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, typed.Elem(), seen)
2711
+ case *types.Slice:
2712
+ return o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, typed.Elem(), seen)
2713
+ case *types.Array:
2714
+ return o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, typed.Elem(), seen)
2715
+ case *types.Map:
2716
+ return o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, typed.Key(), seen) ||
2717
+ o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, typed.Elem(), seen)
2718
+ case *types.Struct:
2719
+ for field := range typed.Fields() {
2720
+ if o.protobufTypeScriptAdapterTypeHasCustomJSON(ctx, field.Type(), seen) {
2721
+ return true
2722
+ }
2723
+ }
2724
+ }
2725
+ return false
2726
+ }
2727
+
2728
+ func (o *LoweringOwner) protobufTypeScriptAdapterNamedTypeHasCustomJSON(
2729
+ ctx lowerFileContext,
2730
+ named *types.Named,
2731
+ ) bool {
2732
+ if named == nil {
2733
+ return false
2734
+ }
2735
+ methodSet := types.NewMethodSet(types.NewPointer(named))
2736
+ for _, name := range []string{"MarshalJSON", "MarshalProtoJSON", "UnmarshalJSON", "UnmarshalProtoJSON"} {
2737
+ selection := methodSet.Lookup(nil, name)
2738
+ if selection == nil {
2739
+ continue
2740
+ }
2741
+ method, ok := selection.Obj().(*types.Func)
2742
+ if !ok {
2743
+ continue
2744
+ }
2745
+ sourcePath := sourcePos(ctx.semPkg.source, method.Pos()).file
2746
+ if sourcePath == "" || strings.HasSuffix(sourcePath, ".pb.go") {
2747
+ continue
2748
+ }
2749
+ return true
2750
+ }
2751
+ return false
2752
+ }
2753
+
2448
2754
  func (o *LoweringOwner) lowerEmbeddedMethodForwarders(
2449
2755
  ctx lowerFileContext,
2450
2756
  field semanticField,
@@ -2481,11 +2787,13 @@ func (o *LoweringOwner) lowerEmbeddedMethodForwarders(
2481
2787
  async := o.functionAsync(ctx, method)
2482
2788
  targetType := o.tsEmbeddedForwarderTargetType(ctx, field.typ)
2483
2789
  lowered := loweredFunction{
2484
- async: async,
2485
- name: methodMemberName(method.Name()),
2486
- runtimeName: method.Name(),
2487
- result: asyncResultType("any", async),
2488
- deferState: &loweredDeferState{},
2790
+ async: async,
2791
+ sourcePath: ctx.sourcePath,
2792
+ name: methodMemberName(method.Name()),
2793
+ runtimeName: method.Name(),
2794
+ runtimeSignature: o.runtimeMethodSignature(method, make(map[types.Type]bool)),
2795
+ result: asyncResultType("any", async),
2796
+ deferState: &loweredDeferState{},
2489
2797
  }
2490
2798
  args := make([]string, 0, signature.Params().Len())
2491
2799
  for idx := range signature.Params().Len() {
@@ -2624,6 +2932,7 @@ func (o *LoweringOwner) lowerNamedReceiverMethodDecl(
2624
2932
  exported: ctx.topLevel,
2625
2933
  indexExported: ctx.topLevel && (ast.IsExported(receiver.Obj().Name()) || ast.IsExported(decl.Name.Name)),
2626
2934
  async: async,
2935
+ sourcePath: sourcePos(ctx.semPkg.source, decl.Pos()).file,
2627
2936
  name: methodFunctionName(receiver, decl.Name.Name),
2628
2937
  result: asyncResultType(result, async),
2629
2938
  deferState: deferState,
@@ -2698,12 +3007,16 @@ func (o *LoweringOwner) lowerFuncDecl(ctx lowerFileContext, decl *ast.FuncDecl)
2698
3007
  indexExported: ctx.topLevel && !blankName && !initFunc && (ast.IsExported(decl.Name.Name) || decl.Name.Name == "main"),
2699
3008
  init: initFunc,
2700
3009
  async: async,
3010
+ sourcePath: sourcePos(ctx.semPkg.source, decl.Pos()).file,
2701
3011
  name: name,
2702
3012
  runtimeName: runtimeName,
2703
3013
  result: asyncResultType(result, async),
2704
3014
  deferState: deferState,
2705
3015
  namedResults: o.lowerNamedResults(functionCtx, signature),
2706
3016
  }
3017
+ if decl.Recv != nil {
3018
+ lowered.runtimeSignature = o.runtimeMethodSignature(fnObj, make(map[types.Type]bool))
3019
+ }
2707
3020
  if signature.TypeParams() != nil && signature.TypeParams().Len() != 0 {
2708
3021
  lowered.typeParams = signatureTypeParamNames(signature)
2709
3022
  lowered.params = append(lowered.params, loweredParam{
@@ -2846,6 +3159,9 @@ func expressionUsesObject(ctx lowerFileContext, expr ast.Expr, obj types.Object)
2846
3159
  if expr == nil || obj == nil || ctx.semPkg == nil || ctx.semPkg.source == nil {
2847
3160
  return false
2848
3161
  }
3162
+ if ident, ok := ast.Unparen(expr).(*ast.Ident); ok {
3163
+ return ctx.semPkg.source.TypesInfo.Uses[ident] == obj || ctx.semPkg.source.TypesInfo.Defs[ident] == obj
3164
+ }
2849
3165
  uses := false
2850
3166
  ast.Inspect(expr, func(node ast.Node) bool {
2851
3167
  if uses {
@@ -2925,9 +3241,22 @@ func (ctx lowerFileContext) withDeferState(deferState *loweredDeferState) lowerF
2925
3241
 
2926
3242
  func (ctx lowerFileContext) withLocalScope() lowerFileContext {
2927
3243
  ctx.topLevel = false
3244
+ ctx.functionScopedDecls = false
3245
+ return ctx
3246
+ }
3247
+
3248
+ func (ctx lowerFileContext) withFunctionScopedDecls() lowerFileContext {
3249
+ ctx.functionScopedDecls = true
2928
3250
  return ctx
2929
3251
  }
2930
3252
 
3253
+ func declarationKeyword(ctx lowerFileContext) string {
3254
+ if ctx.functionScopedDecls {
3255
+ return "var "
3256
+ }
3257
+ return "let "
3258
+ }
3259
+
2931
3260
  func (ctx lowerFileContext) withRangeBranch(branch *loweredRangeBranch) lowerFileContext {
2932
3261
  ctx.rangeBranch = branch
2933
3262
  ctx.rangeBreak = true
@@ -3015,6 +3344,10 @@ func (o *LoweringOwner) lowerBlock(ctx lowerFileContext, block *ast.BlockStmt) (
3015
3344
  }
3016
3345
 
3017
3346
  func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]loweredStmt, []Diagnostic) {
3347
+ return o.lowerStmtInto(ctx, stmt, nil)
3348
+ }
3349
+
3350
+ func (o *LoweringOwner) lowerStmtInto(ctx lowerFileContext, stmt ast.Stmt, out []loweredStmt) ([]loweredStmt, []Diagnostic) {
3018
3351
  switch typed := stmt.(type) {
3019
3352
  case *ast.DeclStmt:
3020
3353
  decls, diagnostics := o.lowerDecl(ctx, typed.Decl)
@@ -3030,27 +3363,28 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
3030
3363
  stmts = append(stmts, loweredStmt{text: strings.TrimRight(b.String(), "\n")})
3031
3364
  }
3032
3365
  }
3033
- return stmts, diagnostics
3366
+ return append(out, stmts...), diagnostics
3034
3367
  case *ast.BlockStmt:
3035
3368
  body, diagnostics := o.lowerBlock(ctx, typed)
3036
- return []loweredStmt{{hasBlock: true, children: body}}, diagnostics
3369
+ return append(out, loweredStmt{hasBlock: true, children: body}), diagnostics
3037
3370
  case *ast.AssignStmt:
3038
- return o.lowerAssignStmt(ctx, typed)
3371
+ stmts, diagnostics := o.lowerAssignStmt(ctx, typed)
3372
+ return append(out, stmts...), diagnostics
3039
3373
  case *ast.SendStmt:
3040
3374
  text, diagnostics := o.lowerSendStmt(ctx, typed)
3041
- return []loweredStmt{{text: text}}, diagnostics
3375
+ return append(out, loweredStmt{text: text}), diagnostics
3042
3376
  case *ast.GoStmt:
3043
3377
  text, diagnostics := o.lowerGoStmt(ctx, typed)
3044
- return []loweredStmt{{text: text}}, diagnostics
3378
+ return append(out, loweredStmt{text: text}), diagnostics
3045
3379
  case *ast.DeferStmt:
3046
3380
  text, diagnostics := o.lowerDeferStmt(ctx, typed)
3047
- return []loweredStmt{{text: text}}, diagnostics
3381
+ return append(out, loweredStmt{text: text}), diagnostics
3048
3382
  case *ast.ExprStmt:
3049
3383
  text, diagnostics := o.lowerExpr(ctx, typed.X)
3050
- return []loweredStmt{{text: expressionStmtText(text)}}, diagnostics
3384
+ return append(out, loweredStmt{text: expressionStmtText(text)}), diagnostics
3051
3385
  case *ast.ReturnStmt:
3052
3386
  text, diagnostics := o.lowerReturnStmt(ctx, typed)
3053
- return []loweredStmt{{text: text}}, diagnostics
3387
+ return append(out, loweredStmt{text: text}), diagnostics
3054
3388
  case *ast.IfStmt:
3055
3389
  var diagnostics []Diagnostic
3056
3390
  var init []loweredStmt
@@ -3083,39 +3417,43 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
3083
3417
  }
3084
3418
  if len(init) != 0 {
3085
3419
  init = append(init, stmt)
3086
- return append(initPrelude, loweredStmt{children: init}), diagnostics
3420
+ initPrelude = append(initPrelude, loweredStmt{children: init})
3421
+ return append(out, initPrelude...), diagnostics
3087
3422
  }
3088
- return []loweredStmt{stmt}, diagnostics
3423
+ return append(out, stmt), diagnostics
3089
3424
  case *ast.ForStmt:
3090
3425
  lowered, diagnostics := o.lowerForStmt(ctx, typed)
3091
- return []loweredStmt{lowered}, diagnostics
3426
+ return append(out, lowered), diagnostics
3092
3427
  case *ast.RangeStmt:
3093
3428
  lowered, diagnostics := o.lowerRangeStmt(ctx, typed)
3094
- return []loweredStmt{lowered}, diagnostics
3429
+ return append(out, lowered), diagnostics
3095
3430
  case *ast.SelectStmt:
3096
3431
  lowered, diagnostics := o.lowerSelectStmt(ctx, typed)
3097
- return []loweredStmt{{selectStmt: lowered}}, diagnostics
3432
+ return append(out, loweredStmt{selectStmt: lowered}), diagnostics
3098
3433
  case *ast.SwitchStmt:
3099
- return o.lowerSwitchStmt(ctx, typed)
3434
+ stmts, diagnostics := o.lowerSwitchStmt(ctx, typed)
3435
+ return append(out, stmts...), diagnostics
3100
3436
  case *ast.TypeSwitchStmt:
3101
- return o.lowerTypeSwitchStmt(ctx, typed)
3437
+ stmts, diagnostics := o.lowerTypeSwitchStmt(ctx, typed)
3438
+ return append(out, stmts...), diagnostics
3102
3439
  case *ast.LabeledStmt:
3103
3440
  lowered, diagnostics := o.lowerStmt(ctx, typed.Stmt)
3104
3441
  if len(lowered) != 0 {
3105
3442
  label := safeIdentifier(typed.Label.Name)
3106
3443
  if lowered[0].text == "" {
3107
- return []loweredStmt{{text: label + ":", children: lowered}}, diagnostics
3444
+ return append(out, loweredStmt{text: label + ":", children: lowered}), diagnostics
3108
3445
  }
3109
3446
  if labeledTextCannotPrefix(lowered[0].text) {
3110
- return append([]loweredStmt{{text: label + ":;"}}, lowered...), diagnostics
3447
+ out = append(out, loweredStmt{text: label + ":;"})
3448
+ return append(out, lowered...), diagnostics
3111
3449
  }
3112
3450
  lowered[0].text = label + ": " + lowered[0].text
3113
3451
  }
3114
- return lowered, diagnostics
3452
+ return append(out, lowered...), diagnostics
3115
3453
  case *ast.IncDecStmt:
3116
3454
  if star, ok := unwrapParenExpr(typed.X).(*ast.StarExpr); ok {
3117
3455
  expr, diagnostics := o.lowerPointerStorageExpr(ctx, star.X)
3118
- return []loweredStmt{{text: expr + typed.Tok.String()}}, diagnostics
3456
+ return append(out, loweredStmt{text: expr + typed.Tok.String()}), diagnostics
3119
3457
  }
3120
3458
  if index, ok := unwrapParenExpr(typed.X).(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) {
3121
3459
  right := "1"
@@ -3123,7 +3461,8 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
3123
3461
  if typed.Tok == token.DEC {
3124
3462
  tok = token.SUB_ASSIGN
3125
3463
  }
3126
- return o.lowerMapIndexUpdateStmts(ctx, index, tok, right, ctx.semPkg.source.TypesInfo.TypeOf(typed.X))
3464
+ stmts, diagnostics := o.lowerMapIndexUpdateStmts(ctx, index, tok, right, ctx.semPkg.source.TypesInfo.TypeOf(typed.X))
3465
+ return append(out, stmts...), diagnostics
3127
3466
  }
3128
3467
  if setter, ok := o.packageVarSetterForAssignment(ctx, typed.X); ok {
3129
3468
  expr, diagnostics := o.lowerExpr(ctx, typed.X)
@@ -3131,58 +3470,58 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
3131
3470
  if typed.Tok == token.DEC {
3132
3471
  op = "-"
3133
3472
  }
3134
- return []loweredStmt{{text: setter + "(" + expr + " " + op + " 1)"}}, diagnostics
3473
+ return append(out, loweredStmt{text: setter + "(" + expr + " " + op + " 1)"}), diagnostics
3135
3474
  }
3136
3475
  expr, diagnostics := o.lowerExpr(ctx, typed.X)
3137
- return []loweredStmt{{text: expr + typed.Tok.String()}}, diagnostics
3476
+ return append(out, loweredStmt{text: expr + typed.Tok.String()}), diagnostics
3138
3477
  case *ast.BranchStmt:
3139
3478
  if typed.Label != nil {
3140
3479
  switch typed.Tok {
3141
3480
  case token.BREAK, token.CONTINUE:
3142
- return []loweredStmt{{text: typed.Tok.String() + " " + safeIdentifier(typed.Label.Name)}}, nil
3481
+ return append(out, loweredStmt{text: typed.Tok.String() + " " + safeIdentifier(typed.Label.Name)}), nil
3143
3482
  case token.GOTO:
3144
3483
  label := safeIdentifier(typed.Label.Name)
3145
3484
  if ctx.gotoStateLabels[label] {
3146
- return []loweredStmt{
3147
- {text: ctx.gotoStateVar + " = " + strconv.Quote(label)},
3148
- {text: "continue " + ctx.gotoStateLoop},
3149
- }, nil
3485
+ return append(out,
3486
+ loweredStmt{text: ctx.gotoStateVar + " = " + strconv.Quote(label)},
3487
+ loweredStmt{text: "continue " + ctx.gotoStateLoop},
3488
+ ), nil
3150
3489
  }
3151
3490
  if ctx.forwardGotos[label] {
3152
- return []loweredStmt{{text: "break " + label}}, nil
3491
+ return append(out, loweredStmt{text: "break " + label}), nil
3153
3492
  }
3154
3493
  if ctx.gotoLabels[label] {
3155
- return []loweredStmt{{text: "continue " + label}}, nil
3494
+ return append(out, loweredStmt{text: "continue " + label}), nil
3156
3495
  }
3157
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported goto branch to "+label)}
3496
+ return out, []Diagnostic{loweringUnsupportedAt(ctx, typed, "statement", ctx.semPkg.pkgPath, "unsupported goto branch to "+label)}
3158
3497
  default:
3159
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported labeled branch")}
3498
+ return out, []Diagnostic{loweringUnsupportedAt(ctx, typed, "statement", ctx.semPkg.pkgPath, "unsupported labeled branch")}
3160
3499
  }
3161
3500
  }
3162
3501
  switch typed.Tok {
3163
3502
  case token.BREAK, token.CONTINUE:
3164
3503
  if typed.Tok == token.BREAK && ctx.loopLabel != "" && !ctx.switchBreak {
3165
- return []loweredStmt{{text: "break " + ctx.loopLabel}}, nil
3504
+ return append(out, loweredStmt{text: "break " + ctx.loopLabel}), nil
3166
3505
  }
3167
3506
  if typed.Tok == token.CONTINUE && ctx.loopLabel != "" {
3168
- return []loweredStmt{{text: "continue " + ctx.loopLabel}}, nil
3507
+ return append(out, loweredStmt{text: "continue " + ctx.loopLabel}), nil
3169
3508
  }
3170
3509
  if typed.Tok == token.BREAK && ctx.rangeBranch != nil && ctx.rangeBreak {
3171
- return []loweredStmt{{text: "return false"}}, nil
3510
+ return append(out, loweredStmt{text: "return false"}), nil
3172
3511
  }
3173
3512
  if typed.Tok == token.CONTINUE && ctx.rangeBranch != nil && ctx.rangeContinue {
3174
- return []loweredStmt{{text: "return true"}}, nil
3513
+ return append(out, loweredStmt{text: "return true"}), nil
3175
3514
  }
3176
- return []loweredStmt{{text: typed.Tok.String()}}, nil
3515
+ return append(out, loweredStmt{text: typed.Tok.String()}), nil
3177
3516
  case token.FALLTHROUGH:
3178
- return []loweredStmt{{text: "fallthrough"}}, nil
3517
+ return append(out, loweredStmt{text: "fallthrough"}), nil
3179
3518
  default:
3180
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported branch")}
3519
+ return out, []Diagnostic{loweringUnsupportedAt(ctx, typed, "statement", ctx.semPkg.pkgPath, "unsupported branch")}
3181
3520
  }
3182
3521
  case *ast.EmptyStmt:
3183
- return nil, nil
3522
+ return out, nil
3184
3523
  default:
3185
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported statement kind")}
3524
+ return out, []Diagnostic{loweringUnsupportedAt(ctx, typed, "statement", ctx.semPkg.pkgPath, "unsupported statement kind")}
3186
3525
  }
3187
3526
  }
3188
3527
 
@@ -3213,7 +3552,7 @@ func (o *LoweringOwner) lowerElse(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
3213
3552
  case *ast.IfStmt:
3214
3553
  return o.lowerStmt(ctx, typed)
3215
3554
  default:
3216
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported else statement")}
3555
+ return nil, []Diagnostic{loweringUnsupportedAt(ctx, typed, "statement", ctx.semPkg.pkgPath, "unsupported else statement")}
3217
3556
  }
3218
3557
  }
3219
3558
 
@@ -3337,12 +3676,13 @@ func (o *LoweringOwner) lowerStmtListAfter(
3337
3676
  }
3338
3677
  }
3339
3678
  if stmtCtx, nextCtx, ok := o.lowerDeclStatementContext(ctx, stmt); ok {
3340
- stmtLowered, stmtDiagnostics := o.lowerStmt(stmtCtx, stmt)
3679
+ start := len(lowered)
3680
+ var stmtDiagnostics []Diagnostic
3681
+ lowered, stmtDiagnostics = o.lowerStmtInto(stmtCtx, stmt, lowered)
3341
3682
  diagnostics = append(diagnostics, stmtDiagnostics...)
3342
- if len(stmtLowered) != 0 && len(leading) != 0 {
3343
- stmtLowered[0].leading = append(leading, stmtLowered[0].leading...)
3683
+ if len(lowered) > start && len(leading) != 0 {
3684
+ lowered[start].leading = append(leading, lowered[start].leading...)
3344
3685
  }
3345
- lowered = append(lowered, stmtLowered...)
3346
3686
  ctx = nextCtx
3347
3687
  if endLine := sourceLine(ctx, stmt.End()); endLine != 0 {
3348
3688
  prevEndLine = endLine
@@ -3367,12 +3707,13 @@ func (o *LoweringOwner) lowerStmtListAfter(
3367
3707
  }
3368
3708
  continue
3369
3709
  }
3370
- stmtLowered, stmtDiagnostics := o.lowerStmt(ctx, stmt)
3710
+ start := len(lowered)
3711
+ var stmtDiagnostics []Diagnostic
3712
+ lowered, stmtDiagnostics = o.lowerStmtInto(ctx, stmt, lowered)
3371
3713
  diagnostics = append(diagnostics, stmtDiagnostics...)
3372
- if len(stmtLowered) != 0 && len(leading) != 0 {
3373
- stmtLowered[0].leading = append(leading, stmtLowered[0].leading...)
3714
+ if len(lowered) > start && len(leading) != 0 {
3715
+ lowered[start].leading = append(leading, lowered[start].leading...)
3374
3716
  }
3375
- lowered = append(lowered, stmtLowered...)
3376
3717
  if endLine := sourceLine(ctx, stmt.End()); endLine != 0 {
3377
3718
  prevEndLine = endLine
3378
3719
  }
@@ -3510,7 +3851,7 @@ func (o *LoweringOwner) lowerGotoStateCluster(
3510
3851
  for _, label := range cluster.labels {
3511
3852
  labels[label.name] = true
3512
3853
  }
3513
- stateCtx := ctx.withGotoState(labels, stateVar, loopLabel)
3854
+ stateCtx := ctx.withGotoState(labels, stateVar, loopLabel).withFunctionScopedDecls()
3514
3855
 
3515
3856
  var diagnostics []Diagnostic
3516
3857
  initialState := cluster.labels[0].name
@@ -3606,7 +3947,7 @@ func (o *LoweringOwner) lowerBackwardGotoLoop(
3606
3947
  var lowered []loweredStmt
3607
3948
  var body []loweredStmt
3608
3949
  var diagnostics []Diagnostic
3609
- bodyCtx := ctx.withGotoLabels(gotoLabels)
3950
+ bodyCtx := ctx.withGotoLabels(gotoLabels).withFunctionScopedDecls()
3610
3951
  if initialForwardLabel != "" {
3611
3952
  skipVar := ctx.tempName("Skip")
3612
3953
  init := loweredStmt{text: "let " + skipVar + " = true"}
@@ -3896,7 +4237,7 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3896
4237
  }
3897
4238
  prefix := ""
3898
4239
  if stmt.Tok == token.DEFINE {
3899
- prefix = "let "
4240
+ prefix = declarationKeyword(ctx)
3900
4241
  if !allShortAssignTargetsNew(ctx, stmt.Lhs) || o.tupleDeclarationNeedsElementStatements(ctx, stmt) {
3901
4242
  return o.lowerTupleReassignmentStmt(ctx, stmt, right, diagnostics)
3902
4243
  }
@@ -3968,7 +4309,7 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3968
4309
  if ident, ok := lhs.(*ast.Ident); ok {
3969
4310
  right = o.lowerDeclaredValue(ctx, ident, right)
3970
4311
  }
3971
- stmts = append(stmts, loweredStmt{text: "let " + left + o.shortDeclTypeAnnotation(ctx, lhs, stmt.Rhs[idx]) + " = " + right})
4312
+ stmts = append(stmts, loweredStmt{text: declarationKeyword(ctx) + left + o.shortDeclTypeAnnotation(ctx, lhs, stmt.Rhs[idx]) + " = " + right})
3972
4313
  continue
3973
4314
  }
3974
4315
  if helper, ok := wideIntegerAssignHelper(targetType, stmt.Tok); ok {
@@ -4146,7 +4487,7 @@ func (o *LoweringOwner) lowerChannelReceiveAssignStmt(
4146
4487
  diagnostics = append(diagnostics, leftDiagnostics...)
4147
4488
  prefix := ""
4148
4489
  if stmt.Tok == token.DEFINE {
4149
- prefix = "let "
4490
+ prefix = declarationKeyword(ctx)
4150
4491
  left += o.shortDeclTypeAnnotation(ctx, stmt.Lhs[0], nil)
4151
4492
  value = o.lowerDeclaredValue(ctx, stmt.Lhs[0], value)
4152
4493
  }
@@ -4207,7 +4548,8 @@ func isIdentLikeExpr(expr ast.Expr) bool {
4207
4548
  func shortDeclNeedsTypeAnnotation(typ types.Type) bool {
4208
4549
  switch typed := types.Unalias(typ).Underlying().(type) {
4209
4550
  case *types.Pointer:
4210
- return namedStructType(typed.Elem()) != nil || namedNonStructType(typed.Elem()) != nil
4551
+ _, pointsToArray := types.Unalias(typed.Elem()).Underlying().(*types.Array)
4552
+ return pointsToArray || namedStructType(typed.Elem()) != nil || namedNonStructType(typed.Elem()) != nil
4211
4553
  case *types.Map:
4212
4554
  return true
4213
4555
  case *types.Slice:
@@ -4249,7 +4591,7 @@ func (o *LoweringOwner) lowerTupleTargetAssignmentStmt(
4249
4591
  left, diagnostics := o.lowerAssignmentTarget(ctx, lhs, declare)
4250
4592
  prefix := ""
4251
4593
  if declare {
4252
- prefix = "let "
4594
+ prefix = declarationKeyword(ctx)
4253
4595
  left += o.shortDeclTypeAnnotation(ctx, lhs, nil)
4254
4596
  value = o.lowerDeclaredValue(ctx, lhs, value)
4255
4597
  }
@@ -5439,7 +5781,7 @@ func (o *LoweringOwner) lowerRangeStmt(ctx lowerFileContext, stmt *ast.RangeStmt
5439
5781
  if isFunctionType(rangeType) {
5440
5782
  signature := rangeFunctionSignature(rangeType)
5441
5783
  if signature == nil {
5442
- return loweredStmt{}, append(diagnostics, loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported function range signature"))
5784
+ return loweredStmt{}, append(diagnostics, loweringUnsupportedAt(ctx, stmt, "statement", ctx.semPkg.pkgPath, "unsupported function range signature"))
5443
5785
  }
5444
5786
  lowered, funcDiagnostics := o.lowerRangeFuncStmt(ctx, stmt, rangeValue, signature)
5445
5787
  diagnostics = append(diagnostics, funcDiagnostics...)
@@ -5519,7 +5861,7 @@ func (o *LoweringOwner) lowerRangeFuncStmt(
5519
5861
  ) (loweredStmt, []Diagnostic) {
5520
5862
  yieldSignature, ok := types.Unalias(signature.Params().At(0).Type()).Underlying().(*types.Signature)
5521
5863
  if !ok {
5522
- return loweredStmt{}, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported function range yield signature")}
5864
+ return loweredStmt{}, []Diagnostic{loweringUnsupportedAt(ctx, stmt, "statement", ctx.semPkg.pkgPath, "unsupported function range yield signature")}
5523
5865
  }
5524
5866
  keyName := rangeKeyName(stmt.Key)
5525
5867
  valueName := rangeKeyName(stmt.Value)
@@ -5602,7 +5944,7 @@ func (o *LoweringOwner) lowerSelectStmt(ctx lowerFileContext, stmt *ast.SelectSt
5602
5944
  for _, raw := range stmt.Body.List {
5603
5945
  clause, ok := raw.(*ast.CommClause)
5604
5946
  if !ok {
5605
- diagnostics = append(diagnostics, loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported select clause"))
5947
+ diagnostics = append(diagnostics, loweringUnsupportedAt(ctx, raw, "statement", ctx.semPkg.pkgPath, "unsupported select clause"))
5606
5948
  continue
5607
5949
  }
5608
5950
  switch comm := clause.Comm.(type) {
@@ -5655,7 +5997,7 @@ func (o *LoweringOwner) lowerSelectStmt(ctx lowerFileContext, stmt *ast.SelectSt
5655
5997
  })
5656
5998
  caseID++
5657
5999
  default:
5658
- diagnostics = append(diagnostics, loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported select communication"))
6000
+ diagnostics = append(diagnostics, loweringUnsupportedAt(ctx, comm, "statement", ctx.semPkg.pkgPath, "unsupported select communication"))
5659
6001
  }
5660
6002
  }
5661
6003
  lowered.returns = selectCasesReturn(lowered.cases)
@@ -5759,7 +6101,7 @@ func (o *LoweringOwner) lowerSelectReceiveComm(
5759
6101
  }
5760
6102
  receive, ok := receiveExpr.(*ast.UnaryExpr)
5761
6103
  if !ok || receive.Op != token.ARROW {
5762
- return "null", nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported select receive")}
6104
+ return "null", nil, []Diagnostic{loweringUnsupportedAt(ctx, receiveExpr, "statement", ctx.semPkg.pkgPath, "unsupported select receive")}
5763
6105
  }
5764
6106
  channel, diagnostics := o.lowerExpr(ctx, receive.X)
5765
6107
  if assign == nil {
@@ -5817,7 +6159,7 @@ func (o *LoweringOwner) lowerSwitchStmt(ctx lowerFileContext, stmt *ast.SwitchSt
5817
6159
  for _, raw := range stmt.Body.List {
5818
6160
  clause, ok := raw.(*ast.CaseClause)
5819
6161
  if !ok {
5820
- diagnostics = append(diagnostics, loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported switch clause"))
6162
+ diagnostics = append(diagnostics, loweringUnsupportedAt(ctx, raw, "statement", ctx.semPkg.pkgPath, "unsupported switch clause"))
5821
6163
  continue
5822
6164
  }
5823
6165
  bodyStmts := clause.Body
@@ -5912,7 +6254,7 @@ func (o *LoweringOwner) lowerTypeSwitchStmt(ctx lowerFileContext, stmt *ast.Type
5912
6254
  valueExpr, varName, varRef, assignDiagnostics := o.lowerTypeSwitchAssign(ctx, stmt.Assign)
5913
6255
  diagnostics = append(diagnostics, assignDiagnostics...)
5914
6256
  if valueExpr == "" {
5915
- return lowered, append(diagnostics, loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported type switch assignment"))
6257
+ return lowered, append(diagnostics, loweringUnsupportedAt(ctx, stmt.Assign, "statement", ctx.semPkg.pkgPath, "unsupported type switch assignment"))
5916
6258
  }
5917
6259
 
5918
6260
  switchIR := &loweredTypeSwitch{
@@ -5923,7 +6265,7 @@ func (o *LoweringOwner) lowerTypeSwitchStmt(ctx lowerFileContext, stmt *ast.Type
5923
6265
  for _, clauseStmt := range stmt.Body.List {
5924
6266
  clause, ok := clauseStmt.(*ast.CaseClause)
5925
6267
  if !ok {
5926
- diagnostics = append(diagnostics, loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported type switch clause"))
6268
+ diagnostics = append(diagnostics, loweringUnsupportedAt(ctx, clauseStmt, "statement", ctx.semPkg.pkgPath, "unsupported type switch clause"))
5927
6269
  continue
5928
6270
  }
5929
6271
  body, bodyDiagnostics := o.lowerStmtList(ctx.withoutRangeBreak().withSwitchBreak(), clause.Body)
@@ -6359,13 +6701,21 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
6359
6701
  return lowerPrefixUnaryExpr(typed.Op, value), diagnostics
6360
6702
  }
6361
6703
  if typed.Op == token.XOR {
6362
- if bits, ok := unsignedIntegerBits(ctx.semPkg.source.TypesInfo.TypeOf(typed)); ok && bits <= 32 {
6363
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
6364
- "(~" + value + ", " + strconv.Itoa(bits) + ")", diagnostics
6704
+ if bits, ok := unsignedIntegerBits(ctx.semPkg.source.TypesInfo.TypeOf(typed)); ok {
6705
+ if bits <= 32 {
6706
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
6707
+ "(~" + value + ", " + strconv.Itoa(bits) + ")", diagnostics
6708
+ }
6709
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint64Xor) +
6710
+ "(" + value + ", -1n)", diagnostics
6711
+ }
6712
+ if bits, ok := signedIntegerBits(ctx.semPkg.source.TypesInfo.TypeOf(typed)); ok && bits > 32 {
6713
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperInt64Xor) +
6714
+ "(" + value + ", -1n)", diagnostics
6365
6715
  }
6366
6716
  return "~" + value, diagnostics
6367
6717
  }
6368
- return value, append(diagnostics, loweringUnsupported("expression", ctx.semPkg.pkgPath, "unsupported unary operator"))
6718
+ return value, append(diagnostics, loweringUnsupportedAt(ctx, typed, "expression", ctx.semPkg.pkgPath, "unsupported unary operator"))
6369
6719
  case *ast.StarExpr:
6370
6720
  return o.lowerPointerValueExpr(ctx, typed.X)
6371
6721
  case *ast.ParenExpr:
@@ -6389,7 +6739,7 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
6389
6739
  case *ast.IndexListExpr:
6390
6740
  return o.lowerExpr(ctx, typed.X)
6391
6741
  default:
6392
- return "undefined", []Diagnostic{loweringUnsupported("expression", ctx.semPkg.pkgPath, "unsupported expression kind")}
6742
+ return "undefined", []Diagnostic{loweringUnsupportedAt(ctx, typed, "expression", ctx.semPkg.pkgPath, "unsupported expression kind")}
6393
6743
  }
6394
6744
  }
6395
6745
 
@@ -6755,7 +7105,7 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
6755
7105
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperRecover) + "(" + strings.Join(args, ", ") + ")", diagnostics
6756
7106
  case "close":
6757
7107
  if len(args) != 1 {
6758
- return "undefined", append(diagnostics, loweringUnsupported("call", ctx.semPkg.pkgPath, "close requires one argument"))
7108
+ return "undefined", append(diagnostics, loweringUnsupportedAt(ctx, expr, "call", ctx.semPkg.pkgPath, "close requires one argument"))
6759
7109
  }
6760
7110
  return args[0] + "!.close()", diagnostics
6761
7111
  }
@@ -6852,9 +7202,9 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
6852
7202
  call := o.lowerCallableExpr(ctx, expr.Fun, callee) + "(" + strings.Join(args, ", ") + ")"
6853
7203
  return o.awaitCallIfNeeded(ctx, expr.Fun, call), append(diagnostics, calleeDiagnostics...)
6854
7204
  }
6855
- return "undefined", append(diagnostics, loweringUnsupported("call", ctx.semPkg.pkgPath, fmt.Sprintf("unsupported call target %T", expr.Fun)))
7205
+ return "undefined", append(diagnostics, loweringUnsupportedAt(ctx, expr.Fun, "call", ctx.semPkg.pkgPath, fmt.Sprintf("unsupported call target %T", expr.Fun)))
6856
7206
  }
6857
- return "undefined", append(diagnostics, loweringUnsupported("call", ctx.semPkg.pkgPath, fmt.Sprintf("unsupported call target %T", expr.Fun)))
7207
+ return "undefined", append(diagnostics, loweringUnsupportedAt(ctx, expr.Fun, "call", ctx.semPkg.pkgPath, fmt.Sprintf("unsupported call target %T", expr.Fun)))
6858
7208
  }
6859
7209
 
6860
7210
  func (o *LoweringOwner) lowerCallableExpr(ctx lowerFileContext, expr ast.Expr, callee string) string {
@@ -7143,11 +7493,11 @@ func unsafePackageFunction(ctx lowerFileContext, expr ast.Expr, name string) boo
7143
7493
 
7144
7494
  func (o *LoweringOwner) lowerMakeExpr(ctx lowerFileContext, expr *ast.CallExpr) (string, []Diagnostic) {
7145
7495
  if len(expr.Args) < 1 {
7146
- return "undefined", []Diagnostic{loweringUnsupported("call", ctx.semPkg.pkgPath, "make requires a type argument")}
7496
+ return "undefined", []Diagnostic{loweringUnsupportedAt(ctx, expr, "call", ctx.semPkg.pkgPath, "make requires a type argument")}
7147
7497
  }
7148
7498
  targetType := typeFromExpr(ctx, expr.Args[0])
7149
7499
  if targetType == nil {
7150
- return "undefined", []Diagnostic{loweringUnsupported("call", ctx.semPkg.pkgPath, "make requires a type expression")}
7500
+ return "undefined", []Diagnostic{loweringUnsupportedAt(ctx, expr.Args[0], "call", ctx.semPkg.pkgPath, "make requires a type expression")}
7151
7501
  }
7152
7502
  switch typed := types.Unalias(targetType).Underlying().(type) {
7153
7503
  case *types.Slice:
@@ -7200,13 +7550,13 @@ func (o *LoweringOwner) lowerMakeExpr(ctx lowerFileContext, expr *ast.CallExpr)
7200
7550
  "<" + o.tsTypeFor(ctx, typed.Elem()) + ">(" + capacity + ", " +
7201
7551
  o.lowerZeroValueExprFor(ctx, typed.Elem()) + ", " + strconv.Quote(channelDirectionString(typed.Dir())) + ")", diagnostics
7202
7552
  default:
7203
- return "undefined", []Diagnostic{loweringUnsupported("call", ctx.semPkg.pkgPath, "unsupported make type")}
7553
+ return "undefined", []Diagnostic{loweringUnsupportedAt(ctx, expr.Args[0], "call", ctx.semPkg.pkgPath, "unsupported make type")}
7204
7554
  }
7205
7555
  }
7206
7556
 
7207
7557
  func (o *LoweringOwner) lowerNewExpr(ctx lowerFileContext, expr *ast.CallExpr) (string, []Diagnostic) {
7208
7558
  if len(expr.Args) != 1 {
7209
- return "undefined", []Diagnostic{loweringUnsupported("call", ctx.semPkg.pkgPath, "new requires one type argument")}
7559
+ return "undefined", []Diagnostic{loweringUnsupportedAt(ctx, expr, "call", ctx.semPkg.pkgPath, "new requires one type argument")}
7210
7560
  }
7211
7561
  typ := typeFromExpr(ctx, expr.Args[0])
7212
7562
  if named := namedStructType(typ); named != nil {
@@ -7222,7 +7572,7 @@ func (o *LoweringOwner) lowerConversionExpr(
7222
7572
  targetType types.Type,
7223
7573
  ) (string, []Diagnostic) {
7224
7574
  if len(expr.Args) != 1 {
7225
- return "undefined", []Diagnostic{loweringUnsupported("call", ctx.semPkg.pkgPath, "unsupported conversion arity")}
7575
+ return "undefined", []Diagnostic{loweringUnsupportedAt(ctx, expr, "call", ctx.semPkg.pkgPath, "unsupported conversion arity")}
7226
7576
  }
7227
7577
  value, diagnostics := o.lowerExpr(ctx, expr.Args[0])
7228
7578
  sourceType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Args[0])
@@ -7317,8 +7667,10 @@ func (o *LoweringOwner) lowerConversionExpr(
7317
7667
  }
7318
7668
  }
7319
7669
  if named := namedFunctionType(targetType); named != nil {
7670
+ typeName := runtimeNamedTypeName(named)
7320
7671
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedFunction) +
7321
- "(" + value + ", " + strconv.Quote(runtimeNamedTypeName(named)) + ")", diagnostics
7672
+ "(" + value + ", " + strconv.Quote(typeName) + ", " +
7673
+ o.runtimeFunctionTypeInfo(named.Underlying().(*types.Signature), typeName) + ")", diagnostics
7322
7674
  }
7323
7675
  if named := namedNonStructType(targetType); named != nil {
7324
7676
  if _, ok := named.Underlying().(*types.Slice); ok {
@@ -8191,7 +8543,7 @@ func (o *LoweringOwner) lowerAddressExpr(ctx lowerFileContext, expr ast.Expr) (s
8191
8543
  case *ast.IndexExpr:
8192
8544
  return o.lowerIndexAddressExpr(ctx, typed)
8193
8545
  default:
8194
- return "undefined", []Diagnostic{loweringUnsupported("expression", ctx.semPkg.pkgPath, "unsupported address expression")}
8546
+ return "undefined", []Diagnostic{loweringUnsupportedAt(ctx, typed, "expression", ctx.semPkg.pkgPath, "unsupported address expression")}
8195
8547
  }
8196
8548
  }
8197
8549
 
@@ -8250,7 +8602,7 @@ func (o *LoweringOwner) lowerIndexAddressExpr(ctx lowerFileContext, expr *ast.In
8250
8602
  diagnostics := append(targetDiagnostics, indexDiagnostics...)
8251
8603
  targetType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
8252
8604
  if isStringType(targetType) || isMapType(targetType) {
8253
- return "undefined", append(diagnostics, loweringUnsupported("expression", ctx.semPkg.pkgPath, "unsupported address expression"))
8605
+ return "undefined", append(diagnostics, loweringUnsupportedAt(ctx, expr, "expression", ctx.semPkg.pkgPath, "unsupported address expression"))
8254
8606
  }
8255
8607
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperIndexRef) + "(" + o.lowerIndexTarget(ctx, target, targetType) + ", " + index + ")", diagnostics
8256
8608
  }
@@ -8278,7 +8630,7 @@ func (o *LoweringOwner) lowerUnsafePointerIntegerExpr(
8278
8630
  if !ok || len(call.Args) != 1 || !isUnsafePointerType(typeFromExpr(ctx, call.Fun)) {
8279
8631
  return "", nil, false
8280
8632
  }
8281
- return o.lowerIndexAddressIntegerExpr(ctx, call.Args[0])
8633
+ return o.lowerIndexByteAddressIntegerExpr(ctx, call.Args[0])
8282
8634
  }
8283
8635
 
8284
8636
  func (o *LoweringOwner) lowerIndexAddressIntegerExpr(
@@ -8304,6 +8656,30 @@ func (o *LoweringOwner) lowerIndexAddressIntegerExpr(
8304
8656
  "(" + o.lowerIndexTarget(ctx, target, targetType) + ", " + index + ")", diagnostics, true
8305
8657
  }
8306
8658
 
8659
+ func (o *LoweringOwner) lowerIndexByteAddressIntegerExpr(
8660
+ ctx lowerFileContext,
8661
+ expr ast.Expr,
8662
+ ) (string, []Diagnostic, bool) {
8663
+ address, ok := unwrapParenExpr(expr).(*ast.UnaryExpr)
8664
+ if !ok || address.Op != token.AND {
8665
+ return "", nil, false
8666
+ }
8667
+ indexExpr, ok := unwrapParenExpr(address.X).(*ast.IndexExpr)
8668
+ if !ok {
8669
+ return "", nil, false
8670
+ }
8671
+ target, targetDiagnostics := o.lowerExpr(ctx, indexExpr.X)
8672
+ index, indexDiagnostics := o.lowerExpr(ctx, indexExpr.Index)
8673
+ diagnostics := append(targetDiagnostics, indexDiagnostics...)
8674
+ targetType := ctx.semPkg.source.TypesInfo.TypeOf(indexExpr.X)
8675
+ if isStringType(targetType) || isMapType(targetType) {
8676
+ return "", diagnostics, false
8677
+ }
8678
+ elementSize := goScriptElementByteSize(ctx, indexElementType(targetType))
8679
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperIndexByteAddress) +
8680
+ "(" + o.lowerIndexTarget(ctx, target, targetType) + ", " + index + ", " + strconv.FormatInt(elementSize, 10) + ")", diagnostics, true
8681
+ }
8682
+
8307
8683
  func (o *LoweringOwner) lowerPointerValueExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
8308
8684
  if value, diagnostics, ok := o.lowerUnsafeStringPointerValue(ctx, expr); ok {
8309
8685
  return value, diagnostics
@@ -8311,6 +8687,12 @@ func (o *LoweringOwner) lowerPointerValueExpr(ctx lowerFileContext, expr ast.Exp
8311
8687
  if value, diagnostics, ok := o.lowerUnsafeStringByteSlicePointerValue(ctx, expr); ok {
8312
8688
  return value, diagnostics
8313
8689
  }
8690
+ if ref, diagnostics, ok := o.lowerUnsafeArrayPointerRefExpr(ctx, expr); ok {
8691
+ return ref + ".value", diagnostics
8692
+ }
8693
+ if ref, diagnostics, ok := o.lowerUnsafePointerRefExpr(ctx, expr); ok {
8694
+ return ref + ".value", diagnostics
8695
+ }
8314
8696
  base, diagnostics := o.lowerExpr(ctx, expr)
8315
8697
  typeArg := ""
8316
8698
  if pointer, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(expr)).Underlying().(*types.Pointer); ok {
@@ -8442,8 +8824,13 @@ func (o *LoweringOwner) lowerUnsafeArrayPointerConversion(
8442
8824
  return "", nil, false
8443
8825
  }
8444
8826
  ref, diagnostics := o.lowerAddressExpr(ctx, index)
8827
+ sourceElementSize := goScriptElementByteSize(ctx, indexElementType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)))
8828
+ targetElementSize := goScriptElementByteSize(ctx, array.Elem())
8445
8829
  helper := o.runtimeOwner.QualifiedHelper(RuntimeHelperArrayPointerFromIndexRef) +
8446
- "<" + o.tsTypeFor(ctx, array.Elem()) + ">(" + ref + ", " + strconv.FormatInt(array.Len(), 10) + ")"
8830
+ "<" + o.tsTypeFor(ctx, array.Elem()) + ">(" + ref + ", " +
8831
+ strconv.FormatInt(array.Len(), 10) + ", " +
8832
+ strconv.FormatInt(sourceElementSize, 10) + ", " +
8833
+ strconv.FormatInt(targetElementSize, 10) + ")"
8447
8834
  return "(" + helper + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics, true
8448
8835
  }
8449
8836
 
@@ -8537,6 +8924,12 @@ func sameLoweredSourceExpr(ctx lowerFileContext, left ast.Expr, right ast.Expr)
8537
8924
  }
8538
8925
 
8539
8926
  func (o *LoweringOwner) lowerPointerStorageExpr(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
8927
+ if ref, diagnostics, ok := o.lowerUnsafeArrayPointerRefExpr(ctx, expr); ok {
8928
+ return ref + ".value", diagnostics
8929
+ }
8930
+ if ref, diagnostics, ok := o.lowerUnsafePointerRefExpr(ctx, expr); ok {
8931
+ return ref + ".value", diagnostics
8932
+ }
8540
8933
  if ref, diagnostics, ok := o.lowerUnsafePointerStorageExpr(ctx, expr); ok {
8541
8934
  return ref, diagnostics
8542
8935
  }
@@ -8544,6 +8937,42 @@ func (o *LoweringOwner) lowerPointerStorageExpr(ctx lowerFileContext, expr ast.E
8544
8937
  return base + "!.value", diagnostics
8545
8938
  }
8546
8939
 
8940
+ func (o *LoweringOwner) lowerUnsafeArrayPointerRefExpr(
8941
+ ctx lowerFileContext,
8942
+ expr ast.Expr,
8943
+ ) (string, []Diagnostic, bool) {
8944
+ call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
8945
+ if !ok || len(call.Args) != 1 {
8946
+ return "", nil, false
8947
+ }
8948
+ targetType := typeFromExpr(ctx, call.Fun)
8949
+ if targetType == nil {
8950
+ return "", nil, false
8951
+ }
8952
+ return o.lowerUnsafeArrayPointerConversion(ctx, targetType, call.Args[0])
8953
+ }
8954
+
8955
+ func (o *LoweringOwner) lowerUnsafePointerRefExpr(
8956
+ ctx lowerFileContext,
8957
+ expr ast.Expr,
8958
+ ) (string, []Diagnostic, bool) {
8959
+ call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
8960
+ if !ok || len(call.Args) != 1 {
8961
+ return "", nil, false
8962
+ }
8963
+ targetType := typeFromExpr(ctx, call.Fun)
8964
+ if targetType == nil {
8965
+ return "", nil, false
8966
+ }
8967
+ pointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
8968
+ if pointer == nil || !isUnsafePointerType(ctx.semPkg.source.TypesInfo.TypeOf(call.Args[0])) {
8969
+ return "", nil, false
8970
+ }
8971
+ value, diagnostics := o.lowerExpr(ctx, call.Args[0])
8972
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUnsafePointerRef) +
8973
+ "<" + o.tsTypeFor(ctx, pointer.Elem()) + ">(" + value + ")", diagnostics, true
8974
+ }
8975
+
8547
8976
  func (o *LoweringOwner) lowerUnsafePointerStorageExpr(
8548
8977
  ctx lowerFileContext,
8549
8978
  expr ast.Expr,
@@ -8713,15 +9142,11 @@ func (o *LoweringOwner) lowerCompositeLit(
8713
9142
  if mapType, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(lit)).Underlying().(*types.Map); ok {
8714
9143
  return o.lowerMapCompositeLit(ctx, lit, mapType)
8715
9144
  }
8716
- position := sourcePos(ctx.semPkg.source, lit.Pos())
8717
9145
  detail := "unsupported composite literal"
8718
- if position.file != "" {
8719
- detail += " at " + filepath.Base(position.file) + ":" + strconv.Itoa(position.line)
8720
- }
8721
9146
  if typ := ctx.semPkg.source.TypesInfo.TypeOf(lit); typ != nil {
8722
9147
  detail += " of type " + typ.String()
8723
9148
  }
8724
- return "undefined", []Diagnostic{loweringUnsupported("expression", ctx.semPkg.pkgPath, detail)}
9149
+ return "undefined", []Diagnostic{loweringUnsupportedAt(ctx, lit, "expression", ctx.semPkg.pkgPath, detail)}
8725
9150
  }
8726
9151
 
8727
9152
  func (o *LoweringOwner) lowerStructCompositeLit(
@@ -8756,7 +9181,7 @@ func (o *LoweringOwner) lowerStructCompositeLit(
8756
9181
  fieldType = field.Type()
8757
9182
  }
8758
9183
  if fieldName == "" {
8759
- diagnostics = append(diagnostics, loweringUnsupported("expression", ctx.semPkg.pkgPath, "unsupported struct literal field"))
9184
+ diagnostics = append(diagnostics, loweringUnsupportedAt(ctx, elt, "expression", ctx.semPkg.pkgPath, "unsupported struct literal field"))
8760
9185
  continue
8761
9186
  }
8762
9187
  value, valueDiagnostics := o.lowerExpr(ctx, valueExpr)
@@ -8867,7 +9292,7 @@ func (o *LoweringOwner) lowerAnonymousStructCompositeLit(
8867
9292
  fieldType = field.Type()
8868
9293
  }
8869
9294
  if fieldName == "" {
8870
- diagnostics = append(diagnostics, loweringUnsupported("expression", ctx.semPkg.pkgPath, "unsupported anonymous struct literal field"))
9295
+ diagnostics = append(diagnostics, loweringUnsupportedAt(ctx, elt, "expression", ctx.semPkg.pkgPath, "unsupported anonymous struct literal field"))
8871
9296
  continue
8872
9297
  }
8873
9298
  value, valueDiagnostics := o.lowerExpr(ctx, valueExpr)
@@ -8976,7 +9401,7 @@ func (o *LoweringOwner) lowerMapCompositeLit(
8976
9401
  for _, elt := range lit.Elts {
8977
9402
  keyed, ok := elt.(*ast.KeyValueExpr)
8978
9403
  if !ok {
8979
- diagnostics = append(diagnostics, loweringUnsupported("expression", ctx.semPkg.pkgPath, "unsupported map literal entry"))
9404
+ diagnostics = append(diagnostics, loweringUnsupportedAt(ctx, elt, "expression", ctx.semPkg.pkgPath, "unsupported map literal entry"))
8980
9405
  continue
8981
9406
  }
8982
9407
  key, keyDiagnostics := o.lowerExpr(ctx, keyed.Key)
@@ -9444,7 +9869,7 @@ func (o *LoweringOwner) shallowRuntimeTypeInfoExpr(typ types.Type) string {
9444
9869
  case *types.Pointer:
9445
9870
  return "{ kind: " + typeKind + ".Pointer, elemType: { kind: " + typeKind + ".Basic, name: \"unknown\" } }"
9446
9871
  case *types.Struct:
9447
- return "{ kind: " + typeKind + ".Struct, methods: [], fields: {} }"
9872
+ return "{ kind: " + typeKind + ".Struct, methods: [], fields: [] }"
9448
9873
  case *types.Slice:
9449
9874
  return "{ kind: " + typeKind + ".Slice, elemType: { kind: " + typeKind + ".Basic, name: \"unknown\" } }"
9450
9875
  case *types.Array:
@@ -9460,6 +9885,11 @@ func (o *LoweringOwner) shallowRuntimeTypeInfoExpr(typ types.Type) string {
9460
9885
 
9461
9886
  func (o *LoweringOwner) runtimeStructFieldsExpr(structType *types.Struct, seen map[types.Type]bool) string {
9462
9887
  fields := make([]string, 0, structType.NumFields())
9888
+ var vars []*types.Var
9889
+ for field := range structType.Fields() {
9890
+ vars = append(vars, field)
9891
+ }
9892
+ offsets := structFieldOffsets(goScriptTypeSizes(), vars)
9463
9893
  for idx := range structType.NumFields() {
9464
9894
  field := structType.Field(idx)
9465
9895
  fieldName := tsStructFieldName(field.Name(), idx)
@@ -9467,30 +9897,71 @@ func (o *LoweringOwner) runtimeStructFieldsExpr(structType *types.Struct, seen m
9467
9897
  if fieldName != field.Name() {
9468
9898
  runtimeName = field.Name()
9469
9899
  }
9900
+ pkgPath := ""
9901
+ if !field.Exported() && field.Pkg() != nil {
9902
+ pkgPath = field.Pkg().Path()
9903
+ }
9470
9904
  fieldInfo := runtimeStructFieldInfoExpr(
9471
9905
  o.runtimeTypeInfoExprWithSeen(field.Type(), seen),
9906
+ fieldName,
9472
9907
  runtimeName,
9473
9908
  structType.Tag(idx),
9909
+ pkgPath,
9910
+ field.Embedded(),
9911
+ []int{idx},
9912
+ offsets[idx],
9913
+ field.Exported(),
9474
9914
  )
9475
- fields = append(fields, strconv.Quote(fieldName)+": "+fieldInfo)
9915
+ fields = append(fields, fieldInfo)
9476
9916
  }
9477
- return "{" + strings.Join(fields, ", ") + "}"
9917
+ return "[" + strings.Join(fields, ", ") + "]"
9478
9918
  }
9479
9919
 
9480
- func runtimeStructFieldInfoExpr(runtimeType string, runtimeName string, tag string) string {
9481
- if runtimeName == "" && tag == "" {
9482
- return runtimeType
9920
+ func runtimeStructFieldInfoExpr(
9921
+ runtimeType string,
9922
+ storageKey string,
9923
+ runtimeName string,
9924
+ tag string,
9925
+ pkgPath string,
9926
+ anonymous bool,
9927
+ index []int,
9928
+ offset int64,
9929
+ exported bool,
9930
+ ) string {
9931
+ name := runtimeName
9932
+ if name == "" {
9933
+ name = storageKey
9934
+ }
9935
+ fields := []string{
9936
+ "name: " + strconv.Quote(name),
9937
+ "key: " + strconv.Quote(storageKey),
9938
+ "type: " + runtimeType,
9483
9939
  }
9484
- fields := []string{"type: " + runtimeType}
9485
9940
  if runtimeName != "" {
9486
- fields = append(fields, "name: "+strconv.Quote(runtimeName))
9941
+ fields = append(fields, "pkgPath: "+strconv.Quote(pkgPath))
9942
+ } else if pkgPath != "" {
9943
+ fields = append(fields, "pkgPath: "+strconv.Quote(pkgPath))
9487
9944
  }
9488
9945
  if tag != "" {
9489
9946
  fields = append(fields, "tag: "+strconv.Quote(tag))
9490
9947
  }
9948
+ if anonymous {
9949
+ fields = append(fields, "anonymous: true")
9950
+ }
9951
+ fields = append(fields, "index: "+runtimeStructFieldIndexExpr(index))
9952
+ fields = append(fields, "offset: "+strconv.FormatInt(offset, 10))
9953
+ fields = append(fields, "exported: "+strconv.FormatBool(exported))
9491
9954
  return "{ " + strings.Join(fields, ", ") + " }"
9492
9955
  }
9493
9956
 
9957
+ func runtimeStructFieldIndexExpr(index []int) string {
9958
+ values := make([]string, 0, len(index))
9959
+ for _, value := range index {
9960
+ values = append(values, strconv.Itoa(value))
9961
+ }
9962
+ return "[" + strings.Join(values, ", ") + "]"
9963
+ }
9964
+
9494
9965
  func (o *LoweringOwner) runtimeFunctionTypeInfo(signature *types.Signature, name string) string {
9495
9966
  return o.runtimeFunctionTypeInfoWithSeen(signature, name, make(map[types.Type]bool))
9496
9967
  }
@@ -10172,6 +10643,42 @@ func isMapType(typ types.Type) bool {
10172
10643
  return ok
10173
10644
  }
10174
10645
 
10646
+ func indexElementType(typ types.Type) types.Type {
10647
+ if pointer, ok := types.Unalias(typ).Underlying().(*types.Pointer); ok {
10648
+ typ = pointer.Elem()
10649
+ }
10650
+ switch typed := types.Unalias(typ).Underlying().(type) {
10651
+ case *types.Slice:
10652
+ return typed.Elem()
10653
+ case *types.Array:
10654
+ return typed.Elem()
10655
+ default:
10656
+ return nil
10657
+ }
10658
+ }
10659
+
10660
+ func goScriptElementByteSize(ctx lowerFileContext, typ types.Type) int64 {
10661
+ if typ == nil {
10662
+ return 1
10663
+ }
10664
+ if sizes := ctx.semPkg.source.TypesSizes; sizes != nil {
10665
+ if size := sizes.Sizeof(typ); size > 0 {
10666
+ return size
10667
+ }
10668
+ }
10669
+ if bits, ok := integerBits(typ); ok && bits > 0 {
10670
+ return int64((bits + 7) / 8)
10671
+ }
10672
+ if isFloatType(typ) {
10673
+ basic, _ := types.Unalias(typ).Underlying().(*types.Basic)
10674
+ if basic != nil && basic.Kind() == types.Float32 {
10675
+ return 4
10676
+ }
10677
+ return 8
10678
+ }
10679
+ return 1
10680
+ }
10681
+
10175
10682
  func isChannelType(typ types.Type) bool {
10176
10683
  if typ == nil {
10177
10684
  return false
@@ -10245,6 +10752,9 @@ func isFloatType(typ types.Type) bool {
10245
10752
  }
10246
10753
 
10247
10754
  func unsignedIntegerBits(typ types.Type) (int, bool) {
10755
+ if typ == nil {
10756
+ return 0, false
10757
+ }
10248
10758
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10249
10759
  if !ok || basic.Info()&types.IsUnsigned == 0 {
10250
10760
  return 0, false
@@ -10262,6 +10772,9 @@ func unsignedIntegerBits(typ types.Type) (int, bool) {
10262
10772
  }
10263
10773
 
10264
10774
  func signedIntegerBits(typ types.Type) (int, bool) {
10775
+ if typ == nil {
10776
+ return 0, false
10777
+ }
10265
10778
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10266
10779
  if !ok || basic.Info()&types.IsInteger == 0 || basic.Info()&types.IsUnsigned != 0 {
10267
10780
  return 0, false
@@ -10609,16 +11122,28 @@ func (o *LoweringOwner) genericTypeDescriptorExpr(ctx lowerFileContext, typ type
10609
11122
  }
10610
11123
  if methods := o.genericMethodDescriptors(ctx, typ); methods != "" {
10611
11124
  parts = append(parts, "methods: "+methods)
11125
+ if signatures := o.genericMethodSignatureDescriptors(typ); signatures != "" &&
11126
+ genericTypeDescriptorNeedsMethodSignatures(typ) {
11127
+ parts = append(parts, "methodSignatures: "+signatures)
11128
+ }
10612
11129
  }
10613
11130
  return "{ " + strings.Join(parts, ", ") + " }"
10614
11131
  }
10615
11132
 
11133
+ func genericTypeDescriptorNeedsMethodSignatures(typ types.Type) bool {
11134
+ named, _ := genericMethodSetDescriptorTarget(typ)
11135
+ if named == nil {
11136
+ return false
11137
+ }
11138
+ return namedStructType(named) == nil && !isInterfaceType(named)
11139
+ }
11140
+
10616
11141
  func (o *LoweringOwner) genericMethodDescriptors(ctx lowerFileContext, typ types.Type) string {
10617
- named, _ := types.Unalias(typ).(*types.Named)
11142
+ named, methodSetType := genericMethodSetDescriptorTarget(typ)
10618
11143
  if named == nil {
10619
11144
  return ""
10620
11145
  }
10621
- return o.genericMethodDescriptorsForType(ctx, named, named)
11146
+ return o.genericMethodDescriptorsForType(ctx, named, methodSetType)
10622
11147
  }
10623
11148
 
10624
11149
  func (o *LoweringOwner) genericMethodDescriptorsForType(
@@ -10659,6 +11184,33 @@ func (o *LoweringOwner) genericMethodDescriptorsForType(
10659
11184
  return "{" + strings.Join(methods, ", ") + "}"
10660
11185
  }
10661
11186
 
11187
+ func (o *LoweringOwner) genericMethodSignatureDescriptors(typ types.Type) string {
11188
+ _, methodSetType := genericMethodSetDescriptorTarget(typ)
11189
+ if methodSetType == nil {
11190
+ return ""
11191
+ }
11192
+ methodSet := types.NewMethodSet(methodSetType)
11193
+ methods := make([]string, 0, methodSet.Len())
11194
+ for method := range methodSet.Methods() {
11195
+ fn, _ := method.Obj().(*types.Func)
11196
+ if fn != nil {
11197
+ methods = append(methods, o.runtimeMethodSignature(fn, make(map[types.Type]bool)))
11198
+ }
11199
+ }
11200
+ if len(methods) == 0 {
11201
+ return ""
11202
+ }
11203
+ return "[" + strings.Join(methods, ", ") + "]"
11204
+ }
11205
+
11206
+ func genericMethodSetDescriptorTarget(typ types.Type) (*types.Named, types.Type) {
11207
+ named, _ := types.Unalias(typ).(*types.Named)
11208
+ if named == nil {
11209
+ return namedNonStructMethodSetType(typ)
11210
+ }
11211
+ return named, named
11212
+ }
11213
+
10662
11214
  func namedNonStructMethodSetType(typ types.Type) (*types.Named, types.Type) {
10663
11215
  if named := namedNonStructType(typ); named != nil {
10664
11216
  return named, named