goscript 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) 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/compiler/compile-request.go +12 -9
  8. package/compiler/compliance_test.go +0 -1
  9. package/compiler/config.go +2 -0
  10. package/compiler/gotest/request.go +28 -0
  11. package/compiler/gotest/runner.go +353 -27
  12. package/compiler/gotest/runner_test.go +273 -1
  13. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  14. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  15. package/compiler/lowered-program.go +24 -17
  16. package/compiler/lowering.go +392 -127
  17. package/compiler/lowering_bench_test.go +41 -27
  18. package/compiler/override-facts.go +15 -0
  19. package/compiler/override-parity-verifier.go +450 -0
  20. package/compiler/override-parity.go +122 -0
  21. package/compiler/override-registry_test.go +559 -0
  22. package/compiler/protobuf-ts-binding.go +514 -0
  23. package/compiler/protobuf-ts-binding_test.go +172 -0
  24. package/compiler/semantic-model-types.go +9 -4
  25. package/compiler/semantic-model.go +282 -70
  26. package/compiler/semantic-model_test.go +82 -1
  27. package/compiler/service.go +20 -1
  28. package/compiler/skeleton_test.go +62 -8
  29. package/compiler/typescript-emitter.go +128 -13
  30. package/dist/gs/builtin/slice.d.ts +2 -1
  31. package/dist/gs/builtin/slice.js +29 -4
  32. package/dist/gs/builtin/slice.js.map +1 -1
  33. package/dist/gs/builtin/type.d.ts +13 -5
  34. package/dist/gs/builtin/type.js +153 -60
  35. package/dist/gs/builtin/type.js.map +1 -1
  36. package/dist/gs/builtin/varRef.d.ts +11 -0
  37. package/dist/gs/builtin/varRef.js +57 -2
  38. package/dist/gs/builtin/varRef.js.map +1 -1
  39. package/dist/gs/bytes/buffer.gs.js +1 -1
  40. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  41. package/dist/gs/bytes/reader.gs.js +1 -1
  42. package/dist/gs/bytes/reader.gs.js.map +1 -1
  43. package/dist/gs/compress/zlib/index.d.ts +10 -3
  44. package/dist/gs/compress/zlib/index.js +50 -16
  45. package/dist/gs/compress/zlib/index.js.map +1 -1
  46. package/dist/gs/encoding/json/index.d.ts +114 -0
  47. package/dist/gs/encoding/json/index.js +544 -36
  48. package/dist/gs/encoding/json/index.js.map +1 -1
  49. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
  50. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
  51. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  52. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  53. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  54. package/dist/gs/go/scanner/index.d.ts +2 -0
  55. package/dist/gs/go/scanner/index.js +29 -5
  56. package/dist/gs/go/scanner/index.js.map +1 -1
  57. package/dist/gs/go/token/index.js +22 -6
  58. package/dist/gs/go/token/index.js.map +1 -1
  59. package/dist/gs/hash/index.d.ts +6 -0
  60. package/dist/gs/hash/index.js +20 -0
  61. package/dist/gs/hash/index.js.map +1 -1
  62. package/dist/gs/internal/goarch/index.d.ts +43 -3
  63. package/dist/gs/internal/goarch/index.js +42 -10
  64. package/dist/gs/internal/goarch/index.js.map +1 -1
  65. package/dist/gs/io/fs/fs.js +26 -14
  66. package/dist/gs/io/fs/fs.js.map +1 -1
  67. package/dist/gs/io/fs/readdir.js +4 -2
  68. package/dist/gs/io/fs/readdir.js.map +1 -1
  69. package/dist/gs/io/fs/sub.js +8 -1
  70. package/dist/gs/io/fs/sub.js.map +1 -1
  71. package/dist/gs/io/io.d.ts +2 -0
  72. package/dist/gs/io/io.js.map +1 -1
  73. package/dist/gs/math/bits/index.d.ts +5 -0
  74. package/dist/gs/math/bits/index.js +16 -4
  75. package/dist/gs/math/bits/index.js.map +1 -1
  76. package/dist/gs/mime/index.d.ts +16 -0
  77. package/dist/gs/mime/index.js +315 -6
  78. package/dist/gs/mime/index.js.map +1 -1
  79. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  80. package/dist/gs/net/http/httptest/index.js +85 -6
  81. package/dist/gs/net/http/httptest/index.js.map +1 -1
  82. package/dist/gs/net/http/index.d.ts +300 -5
  83. package/dist/gs/net/http/index.js +1598 -58
  84. package/dist/gs/net/http/index.js.map +1 -1
  85. package/dist/gs/os/dir_unix.gs.js +1 -1
  86. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  87. package/dist/gs/os/error.gs.js +1 -1
  88. package/dist/gs/os/error.gs.js.map +1 -1
  89. package/dist/gs/os/exec.gs.d.ts +1 -0
  90. package/dist/gs/os/exec.gs.js +4 -8
  91. package/dist/gs/os/exec.gs.js.map +1 -1
  92. package/dist/gs/os/exec_posix.gs.js +1 -1
  93. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  94. package/dist/gs/os/index.d.ts +1 -1
  95. package/dist/gs/os/index.js +1 -1
  96. package/dist/gs/os/index.js.map +1 -1
  97. package/dist/gs/os/proc.gs.d.ts +4 -0
  98. package/dist/gs/os/proc.gs.js +12 -6
  99. package/dist/gs/os/proc.gs.js.map +1 -1
  100. package/dist/gs/os/root_js.gs.js +1 -1
  101. package/dist/gs/os/root_js.gs.js.map +1 -1
  102. package/dist/gs/os/types.gs.js +1 -1
  103. package/dist/gs/os/types.gs.js.map +1 -1
  104. package/dist/gs/os/types_js.gs.js +1 -1
  105. package/dist/gs/os/types_js.gs.js.map +1 -1
  106. package/dist/gs/os/types_unix.gs.js +1 -1
  107. package/dist/gs/os/types_unix.gs.js.map +1 -1
  108. package/dist/gs/path/path.js +11 -7
  109. package/dist/gs/path/path.js.map +1 -1
  110. package/dist/gs/reflect/index.d.ts +5 -4
  111. package/dist/gs/reflect/index.js +4 -3
  112. package/dist/gs/reflect/index.js.map +1 -1
  113. package/dist/gs/reflect/map.js +15 -0
  114. package/dist/gs/reflect/map.js.map +1 -1
  115. package/dist/gs/reflect/type.d.ts +25 -6
  116. package/dist/gs/reflect/type.js +1418 -228
  117. package/dist/gs/reflect/type.js.map +1 -1
  118. package/dist/gs/reflect/types.d.ts +14 -6
  119. package/dist/gs/reflect/types.js +35 -1
  120. package/dist/gs/reflect/types.js.map +1 -1
  121. package/dist/gs/reflect/value.d.ts +1 -0
  122. package/dist/gs/reflect/value.js +83 -41
  123. package/dist/gs/reflect/value.js.map +1 -1
  124. package/dist/gs/reflect/visiblefields.js +4 -140
  125. package/dist/gs/reflect/visiblefields.js.map +1 -1
  126. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  127. package/dist/gs/runtime/pprof/index.js +50 -30
  128. package/dist/gs/runtime/pprof/index.js.map +1 -1
  129. package/dist/gs/runtime/runtime.js +5 -4
  130. package/dist/gs/runtime/runtime.js.map +1 -1
  131. package/dist/gs/runtime/trace/index.js +5 -19
  132. package/dist/gs/runtime/trace/index.js.map +1 -1
  133. package/dist/gs/strconv/atoi.gs.js +1 -1
  134. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  135. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  136. package/dist/gs/strconv/complex.gs.js +148 -0
  137. package/dist/gs/strconv/complex.gs.js.map +1 -0
  138. package/dist/gs/strconv/index.d.ts +1 -0
  139. package/dist/gs/strconv/index.js +1 -0
  140. package/dist/gs/strconv/index.js.map +1 -1
  141. package/dist/gs/strings/builder.js +1 -1
  142. package/dist/gs/strings/reader.js +9 -5
  143. package/dist/gs/strings/reader.js.map +1 -1
  144. package/dist/gs/strings/replace.js +15 -7
  145. package/dist/gs/strings/replace.js.map +1 -1
  146. package/dist/gs/strings/strings.d.ts +5 -0
  147. package/dist/gs/strings/strings.js +57 -5
  148. package/dist/gs/strings/strings.js.map +1 -1
  149. package/dist/gs/sync/atomic/type.gs.js +9 -9
  150. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  151. package/dist/gs/sync/atomic/value.gs.js +2 -2
  152. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  153. package/dist/gs/syscall/env.js +22 -14
  154. package/dist/gs/syscall/env.js.map +1 -1
  155. package/dist/gs/testing/testing.js +55 -13
  156. package/dist/gs/testing/testing.js.map +1 -1
  157. package/dist/gs/time/time.d.ts +24 -1
  158. package/dist/gs/time/time.js +43 -3
  159. package/dist/gs/time/time.js.map +1 -1
  160. package/dist/gs/unique/index.js +7 -1
  161. package/dist/gs/unique/index.js.map +1 -1
  162. package/go.mod +3 -3
  163. package/go.sum +16 -0
  164. package/gs/builtin/runtime-contract.test.ts +218 -21
  165. package/gs/builtin/slice.ts +44 -4
  166. package/gs/builtin/type.ts +226 -59
  167. package/gs/builtin/varRef.ts +85 -2
  168. package/gs/bytes/buffer.gs.ts +1 -1
  169. package/gs/bytes/reader.gs.ts +1 -1
  170. package/gs/compress/zlib/index.test.ts +62 -1
  171. package/gs/compress/zlib/index.ts +53 -16
  172. package/gs/compress/zlib/parity.json +51 -0
  173. package/gs/encoding/json/index.test.ts +360 -6
  174. package/gs/encoding/json/index.ts +679 -38
  175. package/gs/encoding/json/parity.json +81 -0
  176. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
  177. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
  178. package/gs/github.com/pkg/errors/errors.ts +54 -30
  179. package/gs/go/scanner/index.test.ts +39 -56
  180. package/gs/go/scanner/index.ts +33 -5
  181. package/gs/go/scanner/parity.json +27 -0
  182. package/gs/go/token/index.ts +22 -6
  183. package/gs/hash/index.test.ts +20 -33
  184. package/gs/hash/index.ts +28 -0
  185. package/gs/hash/parity.json +21 -0
  186. package/gs/internal/goarch/index.test.ts +32 -0
  187. package/gs/internal/goarch/index.ts +45 -13
  188. package/gs/internal/goarch/parity.json +144 -0
  189. package/gs/io/fs/fs.ts +26 -14
  190. package/gs/io/fs/readdir.ts +4 -4
  191. package/gs/io/fs/sub.ts +8 -1
  192. package/gs/io/io.ts +1 -0
  193. package/gs/io/parity.json +162 -0
  194. package/gs/math/bits/index.test.ts +14 -1
  195. package/gs/math/bits/index.ts +23 -4
  196. package/gs/math/bits/parity.json +156 -0
  197. package/gs/mime/index.test.ts +90 -0
  198. package/gs/mime/index.ts +369 -6
  199. package/gs/mime/parity.json +36 -0
  200. package/gs/net/http/httptest/index.test.ts +98 -2
  201. package/gs/net/http/httptest/index.ts +101 -6
  202. package/gs/net/http/httptest/parity.json +15 -0
  203. package/gs/net/http/index.test.ts +781 -12
  204. package/gs/net/http/index.ts +1860 -139
  205. package/gs/net/http/meta.json +16 -1
  206. package/gs/net/http/parity.json +193 -0
  207. package/gs/os/dir_unix.gs.ts +1 -1
  208. package/gs/os/error.gs.ts +1 -1
  209. package/gs/os/exec.gs.ts +4 -8
  210. package/gs/os/exec_posix.gs.ts +1 -1
  211. package/gs/os/index.test.ts +9 -0
  212. package/gs/os/index.ts +1 -0
  213. package/gs/os/parity.json +9 -0
  214. package/gs/os/proc.gs.ts +18 -5
  215. package/gs/os/proc.test.ts +26 -0
  216. package/gs/os/root_js.gs.ts +1 -1
  217. package/gs/os/types.gs.ts +1 -1
  218. package/gs/os/types_js.gs.ts +1 -1
  219. package/gs/os/types_unix.gs.ts +1 -1
  220. package/gs/path/path.ts +11 -7
  221. package/gs/reflect/field.test.ts +37 -15
  222. package/gs/reflect/function-types.test.ts +518 -22
  223. package/gs/reflect/index.ts +8 -6
  224. package/gs/reflect/map.ts +20 -0
  225. package/gs/reflect/meta.json +6 -4
  226. package/gs/reflect/parity.json +234 -0
  227. package/gs/reflect/sliceat.test.ts +156 -0
  228. package/gs/reflect/structof.test.ts +401 -0
  229. package/gs/reflect/type.ts +1897 -317
  230. package/gs/reflect/typefor.test.ts +510 -10
  231. package/gs/reflect/types.ts +43 -18
  232. package/gs/reflect/value.ts +105 -45
  233. package/gs/reflect/visiblefields.ts +5 -168
  234. package/gs/runtime/parity.json +24 -0
  235. package/gs/runtime/pprof/index.test.ts +29 -7
  236. package/gs/runtime/pprof/index.ts +56 -30
  237. package/gs/runtime/pprof/parity.json +27 -0
  238. package/gs/runtime/runtime.test.ts +3 -1
  239. package/gs/runtime/runtime.ts +4 -3
  240. package/gs/runtime/trace/index.test.ts +5 -3
  241. package/gs/runtime/trace/index.ts +8 -20
  242. package/gs/runtime/trace/parity.json +36 -0
  243. package/gs/strconv/atoi.gs.ts +1 -1
  244. package/gs/strconv/complex.gs.ts +174 -0
  245. package/gs/strconv/complex.test.ts +65 -0
  246. package/gs/strconv/index.ts +1 -0
  247. package/gs/strconv/parity.json +120 -0
  248. package/gs/strings/builder.ts +1 -1
  249. package/gs/strings/parity.json +186 -0
  250. package/gs/strings/reader.ts +9 -5
  251. package/gs/strings/replace.ts +15 -7
  252. package/gs/strings/strings.test.ts +22 -2
  253. package/gs/strings/strings.ts +64 -6
  254. package/gs/sync/atomic/type.gs.ts +9 -9
  255. package/gs/sync/atomic/value.gs.ts +2 -2
  256. package/gs/syscall/env.ts +29 -14
  257. package/gs/testing/testing.test.ts +67 -0
  258. package/gs/testing/testing.ts +87 -19
  259. package/gs/time/parity.json +225 -0
  260. package/gs/time/time.test.ts +20 -2
  261. package/gs/time/time.ts +49 -7
  262. package/gs/unique/index.ts +7 -1
  263. package/package.json +4 -2
  264. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  265. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -926
  266. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  267. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -38
  268. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1361
  269. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
  270. /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
@@ -24,6 +24,16 @@ type LoweringOwner struct {
24
24
  overrideOwner *OverrideRegistryOwner
25
25
  }
26
26
 
27
+ // LoweringOptions are request-scoped lowering switches.
28
+ type LoweringOptions struct {
29
+ // SourceRoot is the request source root that may contain sibling protobuf TypeScript files.
30
+ SourceRoot string
31
+ // OutputPath is the TypeScript output root used for generated relative imports.
32
+ OutputPath string
33
+ // ProtobufTypeScriptBinding binds .pb.go files to sibling .pb.ts files.
34
+ ProtobufTypeScriptBinding bool
35
+ }
36
+
27
37
  // NewLoweringOwner creates the lowering owner.
28
38
  func NewLoweringOwner(runtimeOwner *RuntimeContractOwner, overrideOwner *OverrideRegistryOwner) *LoweringOwner {
29
39
  if runtimeOwner == nil {
@@ -39,7 +49,7 @@ func NewLoweringOwner(runtimeOwner *RuntimeContractOwner, overrideOwner *Overrid
39
49
  }
40
50
 
41
51
  // Build converts the semantic model into the compiler IR.
42
- func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*LoweredProgram, []Diagnostic) {
52
+ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel, opts ...LoweringOptions) (*LoweredProgram, []Diagnostic) {
43
53
  if err := ctx.Err(); err != nil {
44
54
  return nil, []Diagnostic{{
45
55
  Severity: DiagnosticSeverityError,
@@ -55,7 +65,14 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*Lower
55
65
  }}
56
66
  }
57
67
 
68
+ var options LoweringOptions
69
+ if len(opts) != 0 {
70
+ options = opts[0]
71
+ }
72
+
58
73
  program := &LoweredProgram{}
74
+ lazyPackageVars := make(map[string]map[types.Object]bool, len(model.packages))
75
+ runtimeMethodSets := make(runtimeMethodSetCache)
59
76
  semPkgs := make([]*semanticPackage, 0, len(model.packages))
60
77
  for _, semPkg := range model.packages {
61
78
  semPkgs = append(semPkgs, semPkg)
@@ -70,7 +87,7 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*Lower
70
87
  diagnostics = append(diagnostics, loweringUnsupported("package", semPkg.pkgPath, "missing semantic source package"))
71
88
  continue
72
89
  }
73
- loweredPkg, pkgDiagnostics := o.lowerPackage(model, semPkg)
90
+ loweredPkg, pkgDiagnostics := o.lowerPackage(model, semPkg, lazyPackageVars, runtimeMethodSets, options)
74
91
  diagnostics = append(diagnostics, pkgDiagnostics...)
75
92
  if loweredPkg != nil {
76
93
  program.packages = append(program.packages, loweredPkg)
@@ -82,18 +99,68 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel) (*Lower
82
99
  return program, nil
83
100
  }
84
101
 
85
- func (o *LoweringOwner) lowerPackage(model *SemanticModel, semPkg *semanticPackage) (*loweredPackage, []Diagnostic) {
102
+ func (o *LoweringOwner) lowerPackage(
103
+ model *SemanticModel,
104
+ semPkg *semanticPackage,
105
+ lazyPackageVarsByPkg map[string]map[types.Object]bool,
106
+ runtimeMethodSets runtimeMethodSetCache,
107
+ options LoweringOptions,
108
+ ) (*loweredPackage, []Diagnostic) {
86
109
  loweredPkg := &loweredPackage{
87
110
  pkgPath: semPkg.pkgPath,
88
111
  name: semPkg.name,
89
112
  }
90
113
  declFiles := packageDeclFiles(semPkg)
91
114
  outputNames := packageOutputNames(semPkg)
92
- lazyPackageVars := o.lazyPackageVars(semPkg, declFiles)
93
- var diagnostics []Diagnostic
115
+ protobufBindings, bindingDiagnostics := protobufTypeScriptBindings(semPkg, options)
116
+ for sourcePath, binding := range protobufBindings {
117
+ outputNames[sourcePath] = binding.outputName
118
+ }
119
+ lazyPackageVars := o.packageLazyVars(semPkg, lazyPackageVarsByPkg, declFiles)
120
+ diagnostics := append([]Diagnostic(nil), bindingDiagnostics...)
94
121
  for idx, file := range semPkg.source.Syntax {
95
122
  sourcePath := sourceFilePath(semPkg, idx, file)
96
- loweredFile, fileDiagnostics := o.lowerFile(model, semPkg, file, sourcePath, declFiles, outputNames, lazyPackageVars)
123
+ if options.ProtobufTypeScriptBinding && protobufSRPCHasGoScriptReplacement(sourcePath) {
124
+ stub, stubDiagnostics := lowerProtobufSRPCTypeScriptBindingStub(semPkg, sourcePath, options)
125
+ diagnostics = append(diagnostics, stubDiagnostics...)
126
+ if stub != nil {
127
+ loweredPkg.files = append(loweredPkg.files, stub)
128
+ }
129
+ continue
130
+ }
131
+ if binding, ok := protobufBindings[sourcePath]; ok {
132
+ protobufAdapter := !binding.hasOneof && !strings.HasSuffix(filepath.Base(binding.sourcePath), "_srpc.pb.go")
133
+ loweredFile, fileDiagnostics := o.lowerFile(
134
+ model,
135
+ semPkg,
136
+ file,
137
+ sourcePath,
138
+ declFiles,
139
+ outputNames,
140
+ lazyPackageVars,
141
+ lazyPackageVarsByPkg,
142
+ runtimeMethodSets,
143
+ protobufAdapter,
144
+ )
145
+ diagnostics = append(diagnostics, fileDiagnostics...)
146
+ rewriteProtobufTypeScriptBindingFile(loweredFile, binding)
147
+ if loweredFile != nil {
148
+ loweredPkg.files = append(loweredPkg.files, loweredFile)
149
+ }
150
+ continue
151
+ }
152
+ loweredFile, fileDiagnostics := o.lowerFile(
153
+ model,
154
+ semPkg,
155
+ file,
156
+ sourcePath,
157
+ declFiles,
158
+ outputNames,
159
+ lazyPackageVars,
160
+ lazyPackageVarsByPkg,
161
+ runtimeMethodSets,
162
+ false,
163
+ )
97
164
  diagnostics = append(diagnostics, fileDiagnostics...)
98
165
  if loweredFile != nil {
99
166
  loweredPkg.files = append(loweredPkg.files, loweredFile)
@@ -125,6 +192,9 @@ func (o *LoweringOwner) lowerFile(
125
192
  declFiles map[types.Object]string,
126
193
  outputNames map[string]string,
127
194
  lazyPackageVars map[types.Object]bool,
195
+ lazyPackageVarsByPkg map[string]map[types.Object]bool,
196
+ runtimeMethodSets runtimeMethodSetCache,
197
+ protobufTypeScriptAdapter bool,
128
198
  ) (*loweredFile, []Diagnostic) {
129
199
  associatedMethods := o.methodDeclsForFileTypes(semPkg, file)
130
200
  relevantImportFiles := map[string]bool{sourcePath: true}
@@ -146,7 +216,7 @@ func (o *LoweringOwner) lowerFile(
146
216
  importPaths := make(map[string]string)
147
217
  importNames := make(map[string]string)
148
218
  importObjects := make(map[*types.PkgName]string)
149
- localRefs := o.analyzeLocalFileReferences(semPkg, file, sourcePath, associatedMethods, declFiles, outputNames)
219
+ localRefs := o.analyzeLocalFileReferences(semPkg, file, sourcePath, associatedMethods, declFiles, outputNames, runtimeMethodSets)
150
220
  reservedImportAliases := localRefs.reservedNames
151
221
  seenImport := make(map[string]bool)
152
222
  for idx, importFile := range semPkg.source.Syntax {
@@ -231,18 +301,20 @@ func (o *LoweringOwner) lowerFile(
231
301
  loweredFile.imports = append(loweredFile.imports, localImports...)
232
302
 
233
303
  ctx := lowerFileContext{
234
- model: model,
235
- semPkg: semPkg,
236
- file: file,
237
- importAliases: importAliases,
238
- importPaths: importPaths,
239
- importNames: importNames,
240
- importObjects: importObjects,
241
- sourcePath: sourcePath,
242
- localAliases: localRefs.aliases,
243
- lazyPackageVars: lazyPackageVars,
244
- tempNames: newTempNameOwner(),
245
- topLevel: true,
304
+ model: model,
305
+ semPkg: semPkg,
306
+ file: file,
307
+ importAliases: importAliases,
308
+ importPaths: importPaths,
309
+ importNames: importNames,
310
+ importObjects: importObjects,
311
+ sourcePath: sourcePath,
312
+ localAliases: localRefs.aliases,
313
+ lazyPackageVars: lazyPackageVars,
314
+ lazyPackageVarsByPkg: lazyPackageVarsByPkg,
315
+ tempNames: newTempNameOwner(),
316
+ topLevel: true,
317
+ protobufTSAdapter: protobufTypeScriptAdapter,
246
318
  }
247
319
  var diagnostics []Diagnostic
248
320
  var packageInitCalls []string
@@ -451,6 +523,24 @@ type localFileReferenceAnalysis struct {
451
523
  implicitRuntime map[string]bool
452
524
  }
453
525
 
526
+ type runtimeMethodSetCache map[*types.Named][]types.Object
527
+
528
+ func (c runtimeMethodSetCache) methods(named *types.Named) []types.Object {
529
+ if named == nil {
530
+ return nil
531
+ }
532
+ if methods, ok := c[named]; ok {
533
+ return methods
534
+ }
535
+ methodSet := types.NewMethodSet(types.NewPointer(named))
536
+ methods := make([]types.Object, 0, methodSet.Len())
537
+ for method := range methodSet.Methods() {
538
+ methods = append(methods, method.Obj())
539
+ }
540
+ c[named] = methods
541
+ return methods
542
+ }
543
+
454
544
  func (o *LoweringOwner) analyzeLocalFileReferences(
455
545
  semPkg *semanticPackage,
456
546
  file *ast.File,
@@ -458,6 +548,7 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
458
548
  associatedMethods []*ast.FuncDecl,
459
549
  declFiles map[types.Object]string,
460
550
  outputNames map[string]string,
551
+ runtimeMethodSets runtimeMethodSetCache,
461
552
  ) localFileReferenceAnalysis {
462
553
  analysis := localFileReferenceAnalysis{
463
554
  reservedNames: make(map[string]bool),
@@ -469,6 +560,8 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
469
560
  }
470
561
  seenObjects := make(map[types.Object]bool)
471
562
  seenTypes := make(map[types.Type]bool)
563
+ seenRuntimeTypes := make(map[types.Type]bool)
564
+ seenRuntimeOwnerTypes := make(map[types.Type]bool)
472
565
  var addTypeDeps func(typ types.Type)
473
566
  var addRuntimeTypeDeps func(typ types.Type)
474
567
  var addRuntimeTypeOwnerDeps func(typ types.Type)
@@ -636,6 +729,10 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
636
729
  if typ == nil {
637
730
  return
638
731
  }
732
+ if seenRuntimeTypes[typ] {
733
+ return
734
+ }
735
+ seenRuntimeTypes[typ] = true
639
736
  if alias, ok := typ.(*types.Alias); ok {
640
737
  addObject(alias.Obj(), true)
641
738
  if args := alias.TypeArgs(); args != nil {
@@ -651,9 +748,8 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
651
748
  for method := range named.Methods() {
652
749
  addObject(method, true)
653
750
  }
654
- methodSet := types.NewMethodSet(types.NewPointer(named))
655
- for method := range methodSet.Methods() {
656
- addObject(method.Obj(), true)
751
+ for _, method := range runtimeMethodSets.methods(named) {
752
+ addObject(method, true)
657
753
  }
658
754
  if args := named.TypeArgs(); args != nil {
659
755
  for t := range args.Types() {
@@ -680,6 +776,10 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
680
776
  if typ == nil {
681
777
  return
682
778
  }
779
+ if seenRuntimeOwnerTypes[typ] {
780
+ return
781
+ }
782
+ seenRuntimeOwnerTypes[typ] = true
683
783
  if alias, ok := typ.(*types.Alias); ok {
684
784
  addObject(alias.Obj(), true)
685
785
  if args := alias.TypeArgs(); args != nil {
@@ -773,6 +873,9 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
773
873
  }
774
874
  ast.Inspect(file, inspect)
775
875
  for _, methodDecl := range associatedMethods {
876
+ if sourcePos(semPkg.source, methodDecl.Pos()).file == sourcePath {
877
+ continue
878
+ }
776
879
  ast.Inspect(methodDecl, inspect)
777
880
  }
778
881
  return analysis
@@ -984,36 +1087,39 @@ func safeParamName(param *types.Var, idx int) string {
984
1087
  }
985
1088
 
986
1089
  type lowerFileContext struct {
987
- model *SemanticModel
988
- semPkg *semanticPackage
989
- file *ast.File
990
- importAliases map[string]string
991
- importPaths map[string]string
992
- importNames map[string]string
993
- importObjects map[*types.PkgName]string
994
- sourcePath string
995
- localAliases map[types.Object]string
996
- lazyPackageVars map[types.Object]bool
997
- identAliases map[types.Object]string
998
- identAliasRefs map[types.Object]bool
999
- tempNames *tempNameOwner
1000
- signature *types.Signature
1001
- typeParams map[string]bool
1002
- staticTypeParams map[string]bool
1003
- asyncFunction bool
1004
- functionTypeDepth int
1005
- deferState *loweredDeferState
1006
- rangeBranch *loweredRangeBranch
1007
- rangeBreak bool
1008
- rangeContinue bool
1009
- gotoLabels map[string]bool
1010
- forwardGotos map[string]bool
1011
- gotoStateLabels map[string]bool
1012
- gotoStateVar string
1013
- gotoStateLoop string
1014
- loopLabel string
1015
- switchBreak bool
1016
- topLevel bool
1090
+ model *SemanticModel
1091
+ semPkg *semanticPackage
1092
+ file *ast.File
1093
+ importAliases map[string]string
1094
+ importPaths map[string]string
1095
+ importNames map[string]string
1096
+ importObjects map[*types.PkgName]string
1097
+ sourcePath string
1098
+ localAliases map[types.Object]string
1099
+ lazyPackageVars map[types.Object]bool
1100
+ lazyPackageVarsByPkg map[string]map[types.Object]bool
1101
+ identAliases map[types.Object]string
1102
+ identAliasRefs map[types.Object]bool
1103
+ tempNames *tempNameOwner
1104
+ signature *types.Signature
1105
+ typeParams map[string]bool
1106
+ staticTypeParams map[string]bool
1107
+ asyncFunction bool
1108
+ functionTypeDepth int
1109
+ deferState *loweredDeferState
1110
+ rangeBranch *loweredRangeBranch
1111
+ rangeBreak bool
1112
+ rangeContinue bool
1113
+ gotoLabels map[string]bool
1114
+ forwardGotos map[string]bool
1115
+ gotoStateLabels map[string]bool
1116
+ gotoStateVar string
1117
+ gotoStateLoop string
1118
+ functionScopedDecls bool
1119
+ loopLabel string
1120
+ switchBreak bool
1121
+ topLevel bool
1122
+ protobufTSAdapter bool
1017
1123
  }
1018
1124
 
1019
1125
  type tempNameOwner struct {
@@ -1171,7 +1277,7 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
1171
1277
  if _, ok := obj.(*types.Const); !ok && ctx.model.needsVarRef[obj] {
1172
1278
  value = o.runtimeOwner.QualifiedHelper(RuntimeHelperVarRef) + "(" + value + ")"
1173
1279
  }
1174
- keyword := "let"
1280
+ keyword := strings.TrimSpace(declarationKeyword(ctx))
1175
1281
  if _, ok := obj.(*types.Const); ok || decl.Tok == token.CONST {
1176
1282
  keyword = "const"
1177
1283
  }
@@ -1402,6 +1508,9 @@ func packageDeclFiles(semPkg *semanticPackage) map[types.Object]string {
1402
1508
  if semPkg == nil || semPkg.source == nil {
1403
1509
  return nil
1404
1510
  }
1511
+ if len(semPkg.source.Syntax) <= 1 {
1512
+ return nil
1513
+ }
1405
1514
  declFiles := make(map[types.Object]string, len(semPkg.declarations))
1406
1515
  for _, decl := range semPkg.declarations {
1407
1516
  if decl.object != nil && decl.position.file != "" {
@@ -1423,6 +1532,31 @@ func packageOutputNames(semPkg *semanticPackage) map[string]string {
1423
1532
  return outputNames
1424
1533
  }
1425
1534
 
1535
+ func (o *LoweringOwner) packageLazyVars(
1536
+ semPkg *semanticPackage,
1537
+ cache map[string]map[types.Object]bool,
1538
+ declFiles map[types.Object]string,
1539
+ ) map[types.Object]bool {
1540
+ if semPkg == nil {
1541
+ return nil
1542
+ }
1543
+ if cache == nil {
1544
+ if declFiles == nil {
1545
+ declFiles = packageDeclFiles(semPkg)
1546
+ }
1547
+ return o.lazyPackageVars(semPkg, declFiles)
1548
+ }
1549
+ if lazy, ok := cache[semPkg.pkgPath]; ok {
1550
+ return lazy
1551
+ }
1552
+ if declFiles == nil {
1553
+ declFiles = packageDeclFiles(semPkg)
1554
+ }
1555
+ lazy := o.lazyPackageVars(semPkg, declFiles)
1556
+ cache[semPkg.pkgPath] = lazy
1557
+ return lazy
1558
+ }
1559
+
1426
1560
  func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage, declFiles map[types.Object]string) map[types.Object]bool {
1427
1561
  if semPkg == nil || semPkg.source == nil {
1428
1562
  return nil
@@ -1589,7 +1723,7 @@ func (o *LoweringOwner) packageVarIsLazy(ctx lowerFileContext, obj *types.Var) b
1589
1723
  if semPkg == nil {
1590
1724
  return false
1591
1725
  }
1592
- for lazyObj := range o.lazyPackageVars(semPkg, packageDeclFiles(semPkg)) {
1726
+ for lazyObj := range o.packageLazyVars(semPkg, ctx.lazyPackageVarsByPkg, nil) {
1593
1727
  if lazyObj != nil && lazyObj.Name() == obj.Name() &&
1594
1728
  lazyObj.Pkg() != nil && lazyObj.Pkg().Path() == obj.Pkg().Path() {
1595
1729
  return true
@@ -1606,7 +1740,7 @@ func (o *LoweringOwner) packageVarNameIsLazy(ctx lowerFileContext, pkgPath, name
1606
1740
  if semPkg == nil {
1607
1741
  return false
1608
1742
  }
1609
- for lazyObj := range o.lazyPackageVars(semPkg, packageDeclFiles(semPkg)) {
1743
+ for lazyObj := range o.packageLazyVars(semPkg, ctx.lazyPackageVarsByPkg, nil) {
1610
1744
  if lazyObj != nil && lazyObj.Name() == name {
1611
1745
  return true
1612
1746
  }
@@ -2412,6 +2546,11 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2412
2546
  runtimeType: o.runtimeTypeInfoExpr(field.typ),
2413
2547
  doc: field.doc,
2414
2548
  tag: field.tag,
2549
+ pkgPath: field.pkgPath,
2550
+ index: field.index,
2551
+ offset: field.offset,
2552
+ anonymous: field.embedded,
2553
+ exported: field.exported,
2415
2554
  structValue: structValue,
2416
2555
  arrayValue: isArrayType(field.typ),
2417
2556
  })
@@ -2429,7 +2568,13 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2429
2568
  }
2430
2569
  var diagnostics []Diagnostic
2431
2570
  for _, methodDecl := range methodDecls {
2432
- method, methodDiagnostics := o.lowerFuncDecl(ctx, methodDecl)
2571
+ lowerDecl := methodDecl
2572
+ if ctx.protobufTSAdapter && protobufTypeScriptBindingReplacesMethodName(methodDecl.Name.Name) {
2573
+ bodyless := *methodDecl
2574
+ bodyless.Body = nil
2575
+ lowerDecl = &bodyless
2576
+ }
2577
+ method, methodDiagnostics := o.lowerFuncDecl(ctx, lowerDecl)
2433
2578
  diagnostics = append(diagnostics, methodDiagnostics...)
2434
2579
  if method != nil {
2435
2580
  if method.name == "clone" {
@@ -2481,11 +2626,12 @@ func (o *LoweringOwner) lowerEmbeddedMethodForwarders(
2481
2626
  async := o.functionAsync(ctx, method)
2482
2627
  targetType := o.tsEmbeddedForwarderTargetType(ctx, field.typ)
2483
2628
  lowered := loweredFunction{
2484
- async: async,
2485
- name: methodMemberName(method.Name()),
2486
- runtimeName: method.Name(),
2487
- result: asyncResultType("any", async),
2488
- deferState: &loweredDeferState{},
2629
+ async: async,
2630
+ name: methodMemberName(method.Name()),
2631
+ runtimeName: method.Name(),
2632
+ runtimeSignature: o.runtimeMethodSignature(method, make(map[types.Type]bool)),
2633
+ result: asyncResultType("any", async),
2634
+ deferState: &loweredDeferState{},
2489
2635
  }
2490
2636
  args := make([]string, 0, signature.Params().Len())
2491
2637
  for idx := range signature.Params().Len() {
@@ -2704,6 +2850,9 @@ func (o *LoweringOwner) lowerFuncDecl(ctx lowerFileContext, decl *ast.FuncDecl)
2704
2850
  deferState: deferState,
2705
2851
  namedResults: o.lowerNamedResults(functionCtx, signature),
2706
2852
  }
2853
+ if decl.Recv != nil {
2854
+ lowered.runtimeSignature = o.runtimeMethodSignature(fnObj, make(map[types.Type]bool))
2855
+ }
2707
2856
  if signature.TypeParams() != nil && signature.TypeParams().Len() != 0 {
2708
2857
  lowered.typeParams = signatureTypeParamNames(signature)
2709
2858
  lowered.params = append(lowered.params, loweredParam{
@@ -2846,6 +2995,9 @@ func expressionUsesObject(ctx lowerFileContext, expr ast.Expr, obj types.Object)
2846
2995
  if expr == nil || obj == nil || ctx.semPkg == nil || ctx.semPkg.source == nil {
2847
2996
  return false
2848
2997
  }
2998
+ if ident, ok := ast.Unparen(expr).(*ast.Ident); ok {
2999
+ return ctx.semPkg.source.TypesInfo.Uses[ident] == obj || ctx.semPkg.source.TypesInfo.Defs[ident] == obj
3000
+ }
2849
3001
  uses := false
2850
3002
  ast.Inspect(expr, func(node ast.Node) bool {
2851
3003
  if uses {
@@ -2925,9 +3077,22 @@ func (ctx lowerFileContext) withDeferState(deferState *loweredDeferState) lowerF
2925
3077
 
2926
3078
  func (ctx lowerFileContext) withLocalScope() lowerFileContext {
2927
3079
  ctx.topLevel = false
3080
+ ctx.functionScopedDecls = false
3081
+ return ctx
3082
+ }
3083
+
3084
+ func (ctx lowerFileContext) withFunctionScopedDecls() lowerFileContext {
3085
+ ctx.functionScopedDecls = true
2928
3086
  return ctx
2929
3087
  }
2930
3088
 
3089
+ func declarationKeyword(ctx lowerFileContext) string {
3090
+ if ctx.functionScopedDecls {
3091
+ return "var "
3092
+ }
3093
+ return "let "
3094
+ }
3095
+
2931
3096
  func (ctx lowerFileContext) withRangeBranch(branch *loweredRangeBranch) lowerFileContext {
2932
3097
  ctx.rangeBranch = branch
2933
3098
  ctx.rangeBreak = true
@@ -3015,6 +3180,10 @@ func (o *LoweringOwner) lowerBlock(ctx lowerFileContext, block *ast.BlockStmt) (
3015
3180
  }
3016
3181
 
3017
3182
  func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]loweredStmt, []Diagnostic) {
3183
+ return o.lowerStmtInto(ctx, stmt, nil)
3184
+ }
3185
+
3186
+ func (o *LoweringOwner) lowerStmtInto(ctx lowerFileContext, stmt ast.Stmt, out []loweredStmt) ([]loweredStmt, []Diagnostic) {
3018
3187
  switch typed := stmt.(type) {
3019
3188
  case *ast.DeclStmt:
3020
3189
  decls, diagnostics := o.lowerDecl(ctx, typed.Decl)
@@ -3030,27 +3199,28 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
3030
3199
  stmts = append(stmts, loweredStmt{text: strings.TrimRight(b.String(), "\n")})
3031
3200
  }
3032
3201
  }
3033
- return stmts, diagnostics
3202
+ return append(out, stmts...), diagnostics
3034
3203
  case *ast.BlockStmt:
3035
3204
  body, diagnostics := o.lowerBlock(ctx, typed)
3036
- return []loweredStmt{{hasBlock: true, children: body}}, diagnostics
3205
+ return append(out, loweredStmt{hasBlock: true, children: body}), diagnostics
3037
3206
  case *ast.AssignStmt:
3038
- return o.lowerAssignStmt(ctx, typed)
3207
+ stmts, diagnostics := o.lowerAssignStmt(ctx, typed)
3208
+ return append(out, stmts...), diagnostics
3039
3209
  case *ast.SendStmt:
3040
3210
  text, diagnostics := o.lowerSendStmt(ctx, typed)
3041
- return []loweredStmt{{text: text}}, diagnostics
3211
+ return append(out, loweredStmt{text: text}), diagnostics
3042
3212
  case *ast.GoStmt:
3043
3213
  text, diagnostics := o.lowerGoStmt(ctx, typed)
3044
- return []loweredStmt{{text: text}}, diagnostics
3214
+ return append(out, loweredStmt{text: text}), diagnostics
3045
3215
  case *ast.DeferStmt:
3046
3216
  text, diagnostics := o.lowerDeferStmt(ctx, typed)
3047
- return []loweredStmt{{text: text}}, diagnostics
3217
+ return append(out, loweredStmt{text: text}), diagnostics
3048
3218
  case *ast.ExprStmt:
3049
3219
  text, diagnostics := o.lowerExpr(ctx, typed.X)
3050
- return []loweredStmt{{text: expressionStmtText(text)}}, diagnostics
3220
+ return append(out, loweredStmt{text: expressionStmtText(text)}), diagnostics
3051
3221
  case *ast.ReturnStmt:
3052
3222
  text, diagnostics := o.lowerReturnStmt(ctx, typed)
3053
- return []loweredStmt{{text: text}}, diagnostics
3223
+ return append(out, loweredStmt{text: text}), diagnostics
3054
3224
  case *ast.IfStmt:
3055
3225
  var diagnostics []Diagnostic
3056
3226
  var init []loweredStmt
@@ -3083,39 +3253,43 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
3083
3253
  }
3084
3254
  if len(init) != 0 {
3085
3255
  init = append(init, stmt)
3086
- return append(initPrelude, loweredStmt{children: init}), diagnostics
3256
+ initPrelude = append(initPrelude, loweredStmt{children: init})
3257
+ return append(out, initPrelude...), diagnostics
3087
3258
  }
3088
- return []loweredStmt{stmt}, diagnostics
3259
+ return append(out, stmt), diagnostics
3089
3260
  case *ast.ForStmt:
3090
3261
  lowered, diagnostics := o.lowerForStmt(ctx, typed)
3091
- return []loweredStmt{lowered}, diagnostics
3262
+ return append(out, lowered), diagnostics
3092
3263
  case *ast.RangeStmt:
3093
3264
  lowered, diagnostics := o.lowerRangeStmt(ctx, typed)
3094
- return []loweredStmt{lowered}, diagnostics
3265
+ return append(out, lowered), diagnostics
3095
3266
  case *ast.SelectStmt:
3096
3267
  lowered, diagnostics := o.lowerSelectStmt(ctx, typed)
3097
- return []loweredStmt{{selectStmt: lowered}}, diagnostics
3268
+ return append(out, loweredStmt{selectStmt: lowered}), diagnostics
3098
3269
  case *ast.SwitchStmt:
3099
- return o.lowerSwitchStmt(ctx, typed)
3270
+ stmts, diagnostics := o.lowerSwitchStmt(ctx, typed)
3271
+ return append(out, stmts...), diagnostics
3100
3272
  case *ast.TypeSwitchStmt:
3101
- return o.lowerTypeSwitchStmt(ctx, typed)
3273
+ stmts, diagnostics := o.lowerTypeSwitchStmt(ctx, typed)
3274
+ return append(out, stmts...), diagnostics
3102
3275
  case *ast.LabeledStmt:
3103
3276
  lowered, diagnostics := o.lowerStmt(ctx, typed.Stmt)
3104
3277
  if len(lowered) != 0 {
3105
3278
  label := safeIdentifier(typed.Label.Name)
3106
3279
  if lowered[0].text == "" {
3107
- return []loweredStmt{{text: label + ":", children: lowered}}, diagnostics
3280
+ return append(out, loweredStmt{text: label + ":", children: lowered}), diagnostics
3108
3281
  }
3109
3282
  if labeledTextCannotPrefix(lowered[0].text) {
3110
- return append([]loweredStmt{{text: label + ":;"}}, lowered...), diagnostics
3283
+ out = append(out, loweredStmt{text: label + ":;"})
3284
+ return append(out, lowered...), diagnostics
3111
3285
  }
3112
3286
  lowered[0].text = label + ": " + lowered[0].text
3113
3287
  }
3114
- return lowered, diagnostics
3288
+ return append(out, lowered...), diagnostics
3115
3289
  case *ast.IncDecStmt:
3116
3290
  if star, ok := unwrapParenExpr(typed.X).(*ast.StarExpr); ok {
3117
3291
  expr, diagnostics := o.lowerPointerStorageExpr(ctx, star.X)
3118
- return []loweredStmt{{text: expr + typed.Tok.String()}}, diagnostics
3292
+ return append(out, loweredStmt{text: expr + typed.Tok.String()}), diagnostics
3119
3293
  }
3120
3294
  if index, ok := unwrapParenExpr(typed.X).(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) {
3121
3295
  right := "1"
@@ -3123,7 +3297,8 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
3123
3297
  if typed.Tok == token.DEC {
3124
3298
  tok = token.SUB_ASSIGN
3125
3299
  }
3126
- return o.lowerMapIndexUpdateStmts(ctx, index, tok, right, ctx.semPkg.source.TypesInfo.TypeOf(typed.X))
3300
+ stmts, diagnostics := o.lowerMapIndexUpdateStmts(ctx, index, tok, right, ctx.semPkg.source.TypesInfo.TypeOf(typed.X))
3301
+ return append(out, stmts...), diagnostics
3127
3302
  }
3128
3303
  if setter, ok := o.packageVarSetterForAssignment(ctx, typed.X); ok {
3129
3304
  expr, diagnostics := o.lowerExpr(ctx, typed.X)
@@ -3131,58 +3306,58 @@ func (o *LoweringOwner) lowerStmt(ctx lowerFileContext, stmt ast.Stmt) ([]lowere
3131
3306
  if typed.Tok == token.DEC {
3132
3307
  op = "-"
3133
3308
  }
3134
- return []loweredStmt{{text: setter + "(" + expr + " " + op + " 1)"}}, diagnostics
3309
+ return append(out, loweredStmt{text: setter + "(" + expr + " " + op + " 1)"}), diagnostics
3135
3310
  }
3136
3311
  expr, diagnostics := o.lowerExpr(ctx, typed.X)
3137
- return []loweredStmt{{text: expr + typed.Tok.String()}}, diagnostics
3312
+ return append(out, loweredStmt{text: expr + typed.Tok.String()}), diagnostics
3138
3313
  case *ast.BranchStmt:
3139
3314
  if typed.Label != nil {
3140
3315
  switch typed.Tok {
3141
3316
  case token.BREAK, token.CONTINUE:
3142
- return []loweredStmt{{text: typed.Tok.String() + " " + safeIdentifier(typed.Label.Name)}}, nil
3317
+ return append(out, loweredStmt{text: typed.Tok.String() + " " + safeIdentifier(typed.Label.Name)}), nil
3143
3318
  case token.GOTO:
3144
3319
  label := safeIdentifier(typed.Label.Name)
3145
3320
  if ctx.gotoStateLabels[label] {
3146
- return []loweredStmt{
3147
- {text: ctx.gotoStateVar + " = " + strconv.Quote(label)},
3148
- {text: "continue " + ctx.gotoStateLoop},
3149
- }, nil
3321
+ return append(out,
3322
+ loweredStmt{text: ctx.gotoStateVar + " = " + strconv.Quote(label)},
3323
+ loweredStmt{text: "continue " + ctx.gotoStateLoop},
3324
+ ), nil
3150
3325
  }
3151
3326
  if ctx.forwardGotos[label] {
3152
- return []loweredStmt{{text: "break " + label}}, nil
3327
+ return append(out, loweredStmt{text: "break " + label}), nil
3153
3328
  }
3154
3329
  if ctx.gotoLabels[label] {
3155
- return []loweredStmt{{text: "continue " + label}}, nil
3330
+ return append(out, loweredStmt{text: "continue " + label}), nil
3156
3331
  }
3157
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported goto branch to "+label)}
3332
+ return out, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported goto branch to "+label)}
3158
3333
  default:
3159
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported labeled branch")}
3334
+ return out, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported labeled branch")}
3160
3335
  }
3161
3336
  }
3162
3337
  switch typed.Tok {
3163
3338
  case token.BREAK, token.CONTINUE:
3164
3339
  if typed.Tok == token.BREAK && ctx.loopLabel != "" && !ctx.switchBreak {
3165
- return []loweredStmt{{text: "break " + ctx.loopLabel}}, nil
3340
+ return append(out, loweredStmt{text: "break " + ctx.loopLabel}), nil
3166
3341
  }
3167
3342
  if typed.Tok == token.CONTINUE && ctx.loopLabel != "" {
3168
- return []loweredStmt{{text: "continue " + ctx.loopLabel}}, nil
3343
+ return append(out, loweredStmt{text: "continue " + ctx.loopLabel}), nil
3169
3344
  }
3170
3345
  if typed.Tok == token.BREAK && ctx.rangeBranch != nil && ctx.rangeBreak {
3171
- return []loweredStmt{{text: "return false"}}, nil
3346
+ return append(out, loweredStmt{text: "return false"}), nil
3172
3347
  }
3173
3348
  if typed.Tok == token.CONTINUE && ctx.rangeBranch != nil && ctx.rangeContinue {
3174
- return []loweredStmt{{text: "return true"}}, nil
3349
+ return append(out, loweredStmt{text: "return true"}), nil
3175
3350
  }
3176
- return []loweredStmt{{text: typed.Tok.String()}}, nil
3351
+ return append(out, loweredStmt{text: typed.Tok.String()}), nil
3177
3352
  case token.FALLTHROUGH:
3178
- return []loweredStmt{{text: "fallthrough"}}, nil
3353
+ return append(out, loweredStmt{text: "fallthrough"}), nil
3179
3354
  default:
3180
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported branch")}
3355
+ return out, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported branch")}
3181
3356
  }
3182
3357
  case *ast.EmptyStmt:
3183
- return nil, nil
3358
+ return out, nil
3184
3359
  default:
3185
- return nil, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported statement kind")}
3360
+ return out, []Diagnostic{loweringUnsupported("statement", ctx.semPkg.pkgPath, "unsupported statement kind")}
3186
3361
  }
3187
3362
  }
3188
3363
 
@@ -3337,12 +3512,13 @@ func (o *LoweringOwner) lowerStmtListAfter(
3337
3512
  }
3338
3513
  }
3339
3514
  if stmtCtx, nextCtx, ok := o.lowerDeclStatementContext(ctx, stmt); ok {
3340
- stmtLowered, stmtDiagnostics := o.lowerStmt(stmtCtx, stmt)
3515
+ start := len(lowered)
3516
+ var stmtDiagnostics []Diagnostic
3517
+ lowered, stmtDiagnostics = o.lowerStmtInto(stmtCtx, stmt, lowered)
3341
3518
  diagnostics = append(diagnostics, stmtDiagnostics...)
3342
- if len(stmtLowered) != 0 && len(leading) != 0 {
3343
- stmtLowered[0].leading = append(leading, stmtLowered[0].leading...)
3519
+ if len(lowered) > start && len(leading) != 0 {
3520
+ lowered[start].leading = append(leading, lowered[start].leading...)
3344
3521
  }
3345
- lowered = append(lowered, stmtLowered...)
3346
3522
  ctx = nextCtx
3347
3523
  if endLine := sourceLine(ctx, stmt.End()); endLine != 0 {
3348
3524
  prevEndLine = endLine
@@ -3367,12 +3543,13 @@ func (o *LoweringOwner) lowerStmtListAfter(
3367
3543
  }
3368
3544
  continue
3369
3545
  }
3370
- stmtLowered, stmtDiagnostics := o.lowerStmt(ctx, stmt)
3546
+ start := len(lowered)
3547
+ var stmtDiagnostics []Diagnostic
3548
+ lowered, stmtDiagnostics = o.lowerStmtInto(ctx, stmt, lowered)
3371
3549
  diagnostics = append(diagnostics, stmtDiagnostics...)
3372
- if len(stmtLowered) != 0 && len(leading) != 0 {
3373
- stmtLowered[0].leading = append(leading, stmtLowered[0].leading...)
3550
+ if len(lowered) > start && len(leading) != 0 {
3551
+ lowered[start].leading = append(leading, lowered[start].leading...)
3374
3552
  }
3375
- lowered = append(lowered, stmtLowered...)
3376
3553
  if endLine := sourceLine(ctx, stmt.End()); endLine != 0 {
3377
3554
  prevEndLine = endLine
3378
3555
  }
@@ -3510,7 +3687,7 @@ func (o *LoweringOwner) lowerGotoStateCluster(
3510
3687
  for _, label := range cluster.labels {
3511
3688
  labels[label.name] = true
3512
3689
  }
3513
- stateCtx := ctx.withGotoState(labels, stateVar, loopLabel)
3690
+ stateCtx := ctx.withGotoState(labels, stateVar, loopLabel).withFunctionScopedDecls()
3514
3691
 
3515
3692
  var diagnostics []Diagnostic
3516
3693
  initialState := cluster.labels[0].name
@@ -3606,7 +3783,7 @@ func (o *LoweringOwner) lowerBackwardGotoLoop(
3606
3783
  var lowered []loweredStmt
3607
3784
  var body []loweredStmt
3608
3785
  var diagnostics []Diagnostic
3609
- bodyCtx := ctx.withGotoLabels(gotoLabels)
3786
+ bodyCtx := ctx.withGotoLabels(gotoLabels).withFunctionScopedDecls()
3610
3787
  if initialForwardLabel != "" {
3611
3788
  skipVar := ctx.tempName("Skip")
3612
3789
  init := loweredStmt{text: "let " + skipVar + " = true"}
@@ -3896,7 +4073,7 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3896
4073
  }
3897
4074
  prefix := ""
3898
4075
  if stmt.Tok == token.DEFINE {
3899
- prefix = "let "
4076
+ prefix = declarationKeyword(ctx)
3900
4077
  if !allShortAssignTargetsNew(ctx, stmt.Lhs) || o.tupleDeclarationNeedsElementStatements(ctx, stmt) {
3901
4078
  return o.lowerTupleReassignmentStmt(ctx, stmt, right, diagnostics)
3902
4079
  }
@@ -3968,7 +4145,7 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3968
4145
  if ident, ok := lhs.(*ast.Ident); ok {
3969
4146
  right = o.lowerDeclaredValue(ctx, ident, right)
3970
4147
  }
3971
- stmts = append(stmts, loweredStmt{text: "let " + left + o.shortDeclTypeAnnotation(ctx, lhs, stmt.Rhs[idx]) + " = " + right})
4148
+ stmts = append(stmts, loweredStmt{text: declarationKeyword(ctx) + left + o.shortDeclTypeAnnotation(ctx, lhs, stmt.Rhs[idx]) + " = " + right})
3972
4149
  continue
3973
4150
  }
3974
4151
  if helper, ok := wideIntegerAssignHelper(targetType, stmt.Tok); ok {
@@ -4146,7 +4323,7 @@ func (o *LoweringOwner) lowerChannelReceiveAssignStmt(
4146
4323
  diagnostics = append(diagnostics, leftDiagnostics...)
4147
4324
  prefix := ""
4148
4325
  if stmt.Tok == token.DEFINE {
4149
- prefix = "let "
4326
+ prefix = declarationKeyword(ctx)
4150
4327
  left += o.shortDeclTypeAnnotation(ctx, stmt.Lhs[0], nil)
4151
4328
  value = o.lowerDeclaredValue(ctx, stmt.Lhs[0], value)
4152
4329
  }
@@ -4207,7 +4384,8 @@ func isIdentLikeExpr(expr ast.Expr) bool {
4207
4384
  func shortDeclNeedsTypeAnnotation(typ types.Type) bool {
4208
4385
  switch typed := types.Unalias(typ).Underlying().(type) {
4209
4386
  case *types.Pointer:
4210
- return namedStructType(typed.Elem()) != nil || namedNonStructType(typed.Elem()) != nil
4387
+ _, pointsToArray := types.Unalias(typed.Elem()).Underlying().(*types.Array)
4388
+ return pointsToArray || namedStructType(typed.Elem()) != nil || namedNonStructType(typed.Elem()) != nil
4211
4389
  case *types.Map:
4212
4390
  return true
4213
4391
  case *types.Slice:
@@ -4249,7 +4427,7 @@ func (o *LoweringOwner) lowerTupleTargetAssignmentStmt(
4249
4427
  left, diagnostics := o.lowerAssignmentTarget(ctx, lhs, declare)
4250
4428
  prefix := ""
4251
4429
  if declare {
4252
- prefix = "let "
4430
+ prefix = declarationKeyword(ctx)
4253
4431
  left += o.shortDeclTypeAnnotation(ctx, lhs, nil)
4254
4432
  value = o.lowerDeclaredValue(ctx, lhs, value)
4255
4433
  }
@@ -7317,8 +7495,10 @@ func (o *LoweringOwner) lowerConversionExpr(
7317
7495
  }
7318
7496
  }
7319
7497
  if named := namedFunctionType(targetType); named != nil {
7498
+ typeName := runtimeNamedTypeName(named)
7320
7499
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedFunction) +
7321
- "(" + value + ", " + strconv.Quote(runtimeNamedTypeName(named)) + ")", diagnostics
7500
+ "(" + value + ", " + strconv.Quote(typeName) + ", " +
7501
+ o.runtimeFunctionTypeInfo(named.Underlying().(*types.Signature), typeName) + ")", diagnostics
7322
7502
  }
7323
7503
  if named := namedNonStructType(targetType); named != nil {
7324
7504
  if _, ok := named.Underlying().(*types.Slice); ok {
@@ -9444,7 +9624,7 @@ func (o *LoweringOwner) shallowRuntimeTypeInfoExpr(typ types.Type) string {
9444
9624
  case *types.Pointer:
9445
9625
  return "{ kind: " + typeKind + ".Pointer, elemType: { kind: " + typeKind + ".Basic, name: \"unknown\" } }"
9446
9626
  case *types.Struct:
9447
- return "{ kind: " + typeKind + ".Struct, methods: [], fields: {} }"
9627
+ return "{ kind: " + typeKind + ".Struct, methods: [], fields: [] }"
9448
9628
  case *types.Slice:
9449
9629
  return "{ kind: " + typeKind + ".Slice, elemType: { kind: " + typeKind + ".Basic, name: \"unknown\" } }"
9450
9630
  case *types.Array:
@@ -9460,6 +9640,11 @@ func (o *LoweringOwner) shallowRuntimeTypeInfoExpr(typ types.Type) string {
9460
9640
 
9461
9641
  func (o *LoweringOwner) runtimeStructFieldsExpr(structType *types.Struct, seen map[types.Type]bool) string {
9462
9642
  fields := make([]string, 0, structType.NumFields())
9643
+ var vars []*types.Var
9644
+ for field := range structType.Fields() {
9645
+ vars = append(vars, field)
9646
+ }
9647
+ offsets := structFieldOffsets(goScriptTypeSizes(), vars)
9463
9648
  for idx := range structType.NumFields() {
9464
9649
  field := structType.Field(idx)
9465
9650
  fieldName := tsStructFieldName(field.Name(), idx)
@@ -9467,30 +9652,71 @@ func (o *LoweringOwner) runtimeStructFieldsExpr(structType *types.Struct, seen m
9467
9652
  if fieldName != field.Name() {
9468
9653
  runtimeName = field.Name()
9469
9654
  }
9655
+ pkgPath := ""
9656
+ if !field.Exported() && field.Pkg() != nil {
9657
+ pkgPath = field.Pkg().Path()
9658
+ }
9470
9659
  fieldInfo := runtimeStructFieldInfoExpr(
9471
9660
  o.runtimeTypeInfoExprWithSeen(field.Type(), seen),
9661
+ fieldName,
9472
9662
  runtimeName,
9473
9663
  structType.Tag(idx),
9664
+ pkgPath,
9665
+ field.Embedded(),
9666
+ []int{idx},
9667
+ offsets[idx],
9668
+ field.Exported(),
9474
9669
  )
9475
- fields = append(fields, strconv.Quote(fieldName)+": "+fieldInfo)
9670
+ fields = append(fields, fieldInfo)
9476
9671
  }
9477
- return "{" + strings.Join(fields, ", ") + "}"
9672
+ return "[" + strings.Join(fields, ", ") + "]"
9478
9673
  }
9479
9674
 
9480
- func runtimeStructFieldInfoExpr(runtimeType string, runtimeName string, tag string) string {
9481
- if runtimeName == "" && tag == "" {
9482
- return runtimeType
9675
+ func runtimeStructFieldInfoExpr(
9676
+ runtimeType string,
9677
+ storageKey string,
9678
+ runtimeName string,
9679
+ tag string,
9680
+ pkgPath string,
9681
+ anonymous bool,
9682
+ index []int,
9683
+ offset int64,
9684
+ exported bool,
9685
+ ) string {
9686
+ name := runtimeName
9687
+ if name == "" {
9688
+ name = storageKey
9689
+ }
9690
+ fields := []string{
9691
+ "name: " + strconv.Quote(name),
9692
+ "key: " + strconv.Quote(storageKey),
9693
+ "type: " + runtimeType,
9483
9694
  }
9484
- fields := []string{"type: " + runtimeType}
9485
9695
  if runtimeName != "" {
9486
- fields = append(fields, "name: "+strconv.Quote(runtimeName))
9696
+ fields = append(fields, "pkgPath: "+strconv.Quote(pkgPath))
9697
+ } else if pkgPath != "" {
9698
+ fields = append(fields, "pkgPath: "+strconv.Quote(pkgPath))
9487
9699
  }
9488
9700
  if tag != "" {
9489
9701
  fields = append(fields, "tag: "+strconv.Quote(tag))
9490
9702
  }
9703
+ if anonymous {
9704
+ fields = append(fields, "anonymous: true")
9705
+ }
9706
+ fields = append(fields, "index: "+runtimeStructFieldIndexExpr(index))
9707
+ fields = append(fields, "offset: "+strconv.FormatInt(offset, 10))
9708
+ fields = append(fields, "exported: "+strconv.FormatBool(exported))
9491
9709
  return "{ " + strings.Join(fields, ", ") + " }"
9492
9710
  }
9493
9711
 
9712
+ func runtimeStructFieldIndexExpr(index []int) string {
9713
+ values := make([]string, 0, len(index))
9714
+ for _, value := range index {
9715
+ values = append(values, strconv.Itoa(value))
9716
+ }
9717
+ return "[" + strings.Join(values, ", ") + "]"
9718
+ }
9719
+
9494
9720
  func (o *LoweringOwner) runtimeFunctionTypeInfo(signature *types.Signature, name string) string {
9495
9721
  return o.runtimeFunctionTypeInfoWithSeen(signature, name, make(map[types.Type]bool))
9496
9722
  }
@@ -10609,16 +10835,28 @@ func (o *LoweringOwner) genericTypeDescriptorExpr(ctx lowerFileContext, typ type
10609
10835
  }
10610
10836
  if methods := o.genericMethodDescriptors(ctx, typ); methods != "" {
10611
10837
  parts = append(parts, "methods: "+methods)
10838
+ if signatures := o.genericMethodSignatureDescriptors(typ); signatures != "" &&
10839
+ genericTypeDescriptorNeedsMethodSignatures(typ) {
10840
+ parts = append(parts, "methodSignatures: "+signatures)
10841
+ }
10612
10842
  }
10613
10843
  return "{ " + strings.Join(parts, ", ") + " }"
10614
10844
  }
10615
10845
 
10846
+ func genericTypeDescriptorNeedsMethodSignatures(typ types.Type) bool {
10847
+ named, _ := genericMethodSetDescriptorTarget(typ)
10848
+ if named == nil {
10849
+ return false
10850
+ }
10851
+ return namedStructType(named) == nil && !isInterfaceType(named)
10852
+ }
10853
+
10616
10854
  func (o *LoweringOwner) genericMethodDescriptors(ctx lowerFileContext, typ types.Type) string {
10617
- named, _ := types.Unalias(typ).(*types.Named)
10855
+ named, methodSetType := genericMethodSetDescriptorTarget(typ)
10618
10856
  if named == nil {
10619
10857
  return ""
10620
10858
  }
10621
- return o.genericMethodDescriptorsForType(ctx, named, named)
10859
+ return o.genericMethodDescriptorsForType(ctx, named, methodSetType)
10622
10860
  }
10623
10861
 
10624
10862
  func (o *LoweringOwner) genericMethodDescriptorsForType(
@@ -10659,6 +10897,33 @@ func (o *LoweringOwner) genericMethodDescriptorsForType(
10659
10897
  return "{" + strings.Join(methods, ", ") + "}"
10660
10898
  }
10661
10899
 
10900
+ func (o *LoweringOwner) genericMethodSignatureDescriptors(typ types.Type) string {
10901
+ _, methodSetType := genericMethodSetDescriptorTarget(typ)
10902
+ if methodSetType == nil {
10903
+ return ""
10904
+ }
10905
+ methodSet := types.NewMethodSet(methodSetType)
10906
+ methods := make([]string, 0, methodSet.Len())
10907
+ for method := range methodSet.Methods() {
10908
+ fn, _ := method.Obj().(*types.Func)
10909
+ if fn != nil {
10910
+ methods = append(methods, o.runtimeMethodSignature(fn, make(map[types.Type]bool)))
10911
+ }
10912
+ }
10913
+ if len(methods) == 0 {
10914
+ return ""
10915
+ }
10916
+ return "[" + strings.Join(methods, ", ") + "]"
10917
+ }
10918
+
10919
+ func genericMethodSetDescriptorTarget(typ types.Type) (*types.Named, types.Type) {
10920
+ named, _ := types.Unalias(typ).(*types.Named)
10921
+ if named == nil {
10922
+ return namedNonStructMethodSetType(typ)
10923
+ }
10924
+ return named, named
10925
+ }
10926
+
10662
10927
  func namedNonStructMethodSetType(typ types.Type) (*types.Named, types.Type) {
10663
10928
  if named := namedNonStructType(typ); named != nil {
10664
10929
  return named, named