goscript 0.2.3 → 0.2.5

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 (160) hide show
  1. package/README.md +8 -8
  2. package/cmd/go_js_wasm_exec/main.go +1 -1
  3. package/cmd/go_js_wasm_exec/main_test.go +1 -1
  4. package/cmd/goscript/cmd-compile.go +9 -1
  5. package/cmd/goscript/cmd-test.go +1 -1
  6. package/cmd/goscript/cmd_compile_test.go +44 -0
  7. package/cmd/goscript/deps.go +1 -1
  8. package/cmd/goscript-wasm/main.go +2 -2
  9. package/compiler/compile-request.go +19 -0
  10. package/compiler/compile_bench_test.go +121 -0
  11. package/compiler/compliance_test.go +17 -1
  12. package/compiler/config.go +2 -0
  13. package/compiler/gotest/result.go +1 -1
  14. package/compiler/gotest/runner.go +2 -2
  15. package/compiler/gotest/runner_test.go +4 -7
  16. package/compiler/index.test.ts +28 -0
  17. package/compiler/index.ts +32 -16
  18. package/compiler/lowering.go +1236 -143
  19. package/compiler/lowering_bench_test.go +4 -0
  20. package/compiler/override-facts.go +1 -1
  21. package/compiler/override-registry_test.go +125 -0
  22. package/compiler/package-graph.go +92 -0
  23. package/compiler/package-graph_test.go +113 -0
  24. package/compiler/runtime-contract.go +1 -1
  25. package/compiler/semantic-model.go +32 -0
  26. package/compiler/skeleton_test.go +284 -11
  27. package/compiler/wasm/compile.go +1 -1
  28. package/compiler/wasm/compile_test.go +1 -1
  29. package/dist/compiler/index.d.ts +4 -0
  30. package/dist/compiler/index.js +26 -15
  31. package/dist/compiler/index.js.map +1 -1
  32. package/dist/gs/compress/gzip/index.d.ts +41 -0
  33. package/dist/gs/compress/gzip/index.js +235 -0
  34. package/dist/gs/compress/gzip/index.js.map +1 -0
  35. package/dist/gs/database/sql/driver/index.d.ts +165 -0
  36. package/dist/gs/database/sql/driver/index.js +432 -0
  37. package/dist/gs/database/sql/driver/index.js.map +1 -0
  38. package/dist/gs/encoding/binary/index.d.ts +71 -0
  39. package/dist/gs/encoding/binary/index.js +778 -0
  40. package/dist/gs/encoding/binary/index.js.map +1 -0
  41. package/dist/gs/fmt/fmt.js +156 -57
  42. package/dist/gs/fmt/fmt.js.map +1 -1
  43. package/dist/gs/github.com/klauspost/cpuid/v2/index.d.ts +11 -0
  44. package/dist/gs/github.com/klauspost/cpuid/v2/index.js +28 -0
  45. package/dist/gs/github.com/klauspost/cpuid/v2/index.js.map +1 -0
  46. package/dist/gs/github.com/pkg/errors/errors.d.ts +0 -2
  47. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  48. package/dist/gs/github.com/pkg/errors/index.d.ts +2 -1
  49. package/dist/gs/github.com/pkg/errors/index.js +1 -1
  50. package/dist/gs/github.com/pkg/errors/index.js.map +1 -1
  51. package/dist/gs/github.com/pkg/errors/stack.d.ts +8 -19
  52. package/dist/gs/github.com/pkg/errors/stack.js +26 -61
  53. package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
  54. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.d.ts +19 -0
  55. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js +25 -0
  56. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js.map +1 -0
  57. package/dist/gs/golang.org/x/crypto/cryptobyte/index.d.ts +104 -0
  58. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js +1107 -0
  59. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js.map +1 -0
  60. package/dist/gs/golang.org/x/crypto/internal/alias/index.d.ts +3 -0
  61. package/dist/gs/golang.org/x/crypto/internal/alias/index.js +39 -0
  62. package/dist/gs/golang.org/x/crypto/internal/alias/index.js.map +1 -0
  63. package/dist/gs/io/fs/glob.js +1 -1
  64. package/dist/gs/io/fs/glob.js.map +1 -1
  65. package/dist/gs/io/fs/readlink.d.ts +1 -1
  66. package/dist/gs/io/fs/readlink.js +2 -2
  67. package/dist/gs/io/fs/readlink.js.map +1 -1
  68. package/dist/gs/io/fs/stat.d.ts +4 -2
  69. package/dist/gs/io/fs/stat.js +12 -73
  70. package/dist/gs/io/fs/stat.js.map +1 -1
  71. package/dist/gs/io/fs/sub.d.ts +2 -2
  72. package/dist/gs/io/fs/sub.js +7 -7
  73. package/dist/gs/io/fs/sub.js.map +1 -1
  74. package/dist/gs/io/fs/walk.js +1 -1
  75. package/dist/gs/io/fs/walk.js.map +1 -1
  76. package/dist/gs/net/http/index.d.ts +18 -14
  77. package/dist/gs/net/http/index.js +44 -23
  78. package/dist/gs/net/http/index.js.map +1 -1
  79. package/dist/gs/net/http/pprof/index.d.ts +5 -5
  80. package/dist/gs/net/http/pprof/index.js +21 -21
  81. package/dist/gs/net/http/pprof/index.js.map +1 -1
  82. package/dist/gs/runtime/runtime.d.ts +6 -1
  83. package/dist/gs/runtime/runtime.js +15 -8
  84. package/dist/gs/runtime/runtime.js.map +1 -1
  85. package/dist/gs/runtime/trace/index.d.ts +8 -5
  86. package/dist/gs/runtime/trace/index.js +324 -23
  87. package/dist/gs/runtime/trace/index.js.map +1 -1
  88. package/dist/gs/slices/slices.d.ts +2 -1
  89. package/dist/gs/slices/slices.js +9 -3
  90. package/dist/gs/slices/slices.js.map +1 -1
  91. package/dist/gs/sort/search.gs.d.ts +3 -1
  92. package/dist/gs/sort/search.gs.js +18 -53
  93. package/dist/gs/sort/search.gs.js.map +1 -1
  94. package/dist/gs/sync/sync.d.ts +1 -1
  95. package/dist/gs/sync/sync.js +3 -0
  96. package/dist/gs/sync/sync.js.map +1 -1
  97. package/dist/gs/time/time.d.ts +22 -29
  98. package/dist/gs/time/time.js +111 -32
  99. package/dist/gs/time/time.js.map +1 -1
  100. package/dist/gs/unsafe/unsafe.d.ts +3 -2
  101. package/dist/gs/unsafe/unsafe.js.map +1 -1
  102. package/go.mod +7 -5
  103. package/go.sum +12 -26
  104. package/gs/builtin/runtime-contract.test.ts +25 -0
  105. package/gs/compress/gzip/index.test.ts +86 -0
  106. package/gs/compress/gzip/index.ts +297 -0
  107. package/gs/compress/gzip/meta.json +6 -0
  108. package/gs/compress/gzip/parity.json +45 -0
  109. package/gs/database/sql/driver/index.test.ts +88 -0
  110. package/gs/database/sql/driver/index.ts +675 -0
  111. package/gs/database/sql/driver/meta.json +3 -0
  112. package/gs/database/sql/driver/parity.json +144 -0
  113. package/gs/embed/index.test.ts +1 -1
  114. package/gs/encoding/binary/index.test.ts +239 -0
  115. package/gs/encoding/binary/index.ts +999 -0
  116. package/gs/encoding/binary/meta.json +9 -0
  117. package/gs/encoding/binary/parity.json +72 -0
  118. package/gs/fmt/fmt.test.ts +28 -0
  119. package/gs/fmt/fmt.ts +198 -61
  120. package/gs/fmt/meta.json +2 -1
  121. package/gs/github.com/klauspost/cpuid/v2/index.ts +38 -0
  122. package/gs/github.com/klauspost/cpuid/v2/meta.json +3 -0
  123. package/gs/github.com/pkg/errors/errors.ts +1 -2
  124. package/gs/github.com/pkg/errors/index.ts +2 -1
  125. package/gs/github.com/pkg/errors/stack.ts +34 -62
  126. package/gs/golang.org/x/crypto/cryptobyte/asn1/index.test.ts +19 -0
  127. package/gs/golang.org/x/crypto/cryptobyte/asn1/index.ts +29 -0
  128. package/gs/golang.org/x/crypto/cryptobyte/index.test.ts +255 -0
  129. package/gs/golang.org/x/crypto/cryptobyte/index.ts +1441 -0
  130. package/gs/golang.org/x/crypto/cryptobyte/meta.json +3 -0
  131. package/gs/golang.org/x/crypto/internal/alias/index.test.ts +40 -0
  132. package/gs/golang.org/x/crypto/internal/alias/index.ts +40 -0
  133. package/gs/io/fs/glob.ts +1 -1
  134. package/gs/io/fs/meta.json +3 -0
  135. package/gs/io/fs/readlink.test.ts +2 -2
  136. package/gs/io/fs/readlink.ts +5 -2
  137. package/gs/io/fs/stat.test.ts +79 -0
  138. package/gs/io/fs/stat.ts +24 -10
  139. package/gs/io/fs/sub.test.ts +93 -0
  140. package/gs/io/fs/sub.ts +9 -9
  141. package/gs/io/fs/walk.ts +1 -1
  142. package/gs/net/http/index.test.ts +207 -2
  143. package/gs/net/http/index.ts +68 -37
  144. package/gs/net/http/meta.json +3 -1
  145. package/gs/net/http/pprof/index.test.ts +4 -4
  146. package/gs/net/http/pprof/index.ts +30 -27
  147. package/gs/runtime/runtime.test.ts +16 -0
  148. package/gs/runtime/runtime.ts +17 -9
  149. package/gs/runtime/trace/index.test.ts +113 -14
  150. package/gs/runtime/trace/index.ts +384 -34
  151. package/gs/runtime/trace/meta.json +1 -0
  152. package/gs/slices/slices.test.ts +24 -1
  153. package/gs/slices/slices.ts +14 -4
  154. package/gs/sort/meta.json +1 -0
  155. package/gs/sort/search.gs.ts +20 -5
  156. package/gs/sync/sync.ts +4 -1
  157. package/gs/time/time.test.ts +79 -2
  158. package/gs/time/time.ts +133 -33
  159. package/gs/unsafe/unsafe.ts +4 -2
  160. package/package.json +2 -2
@@ -76,6 +76,8 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel, opts ..
76
76
 
77
77
  program := &LoweredProgram{}
78
78
  lazyPackageVars := make(map[string]map[types.Object]bool, len(model.packages))
79
+ asyncLazyFunctionCache := make(map[*types.Func]bool)
80
+ asyncLazyFunctionVisiting := make(map[*types.Func]bool)
79
81
  runtimeMethodSets := make(runtimeMethodSetCache)
80
82
  semPkgs := make([]*semanticPackage, 0, len(model.packages))
81
83
  for _, semPkg := range model.packages {
@@ -91,7 +93,15 @@ func (o *LoweringOwner) Build(ctx context.Context, model *SemanticModel, opts ..
91
93
  diagnostics = append(diagnostics, loweringUnsupported("package", semPkg.pkgPath, "missing semantic source package"))
92
94
  continue
93
95
  }
94
- loweredPkg, pkgDiagnostics := o.lowerPackage(model, semPkg, lazyPackageVars, runtimeMethodSets, options)
96
+ loweredPkg, pkgDiagnostics := o.lowerPackage(
97
+ model,
98
+ semPkg,
99
+ lazyPackageVars,
100
+ asyncLazyFunctionCache,
101
+ asyncLazyFunctionVisiting,
102
+ runtimeMethodSets,
103
+ options,
104
+ )
95
105
  diagnostics = append(diagnostics, pkgDiagnostics...)
96
106
  if loweredPkg != nil {
97
107
  program.packages = append(program.packages, loweredPkg)
@@ -107,6 +117,8 @@ func (o *LoweringOwner) lowerPackage(
107
117
  model *SemanticModel,
108
118
  semPkg *semanticPackage,
109
119
  lazyPackageVarsByPkg map[string]map[types.Object]bool,
120
+ asyncLazyFunctionCache map[*types.Func]bool,
121
+ asyncLazyFunctionVisiting map[*types.Func]bool,
110
122
  runtimeMethodSets runtimeMethodSetCache,
111
123
  options LoweringOptions,
112
124
  ) (*loweredPackage, []Diagnostic) {
@@ -143,6 +155,8 @@ func (o *LoweringOwner) lowerPackage(
143
155
  outputNames,
144
156
  lazyPackageVars,
145
157
  lazyPackageVarsByPkg,
158
+ asyncLazyFunctionCache,
159
+ asyncLazyFunctionVisiting,
146
160
  runtimeMethodSets,
147
161
  protobufAdapter,
148
162
  options.DisplayRoot,
@@ -163,6 +177,8 @@ func (o *LoweringOwner) lowerPackage(
163
177
  outputNames,
164
178
  lazyPackageVars,
165
179
  lazyPackageVarsByPkg,
180
+ asyncLazyFunctionCache,
181
+ asyncLazyFunctionVisiting,
166
182
  runtimeMethodSets,
167
183
  false,
168
184
  options.DisplayRoot,
@@ -199,6 +215,8 @@ func (o *LoweringOwner) lowerFile(
199
215
  outputNames map[string]string,
200
216
  lazyPackageVars map[types.Object]bool,
201
217
  lazyPackageVarsByPkg map[string]map[types.Object]bool,
218
+ asyncLazyFunctionCache map[*types.Func]bool,
219
+ asyncLazyFunctionVisiting map[*types.Func]bool,
202
220
  runtimeMethodSets runtimeMethodSetCache,
203
221
  protobufTypeScriptAdapter bool,
204
222
  displayRoot string,
@@ -308,21 +326,23 @@ func (o *LoweringOwner) lowerFile(
308
326
  loweredFile.imports = append(loweredFile.imports, localImports...)
309
327
 
310
328
  ctx := lowerFileContext{
311
- model: model,
312
- semPkg: semPkg,
313
- file: file,
314
- importAliases: importAliases,
315
- importPaths: importPaths,
316
- importNames: importNames,
317
- importObjects: importObjects,
318
- sourcePath: sourcePath,
319
- localAliases: localRefs.aliases,
320
- lazyPackageVars: lazyPackageVars,
321
- lazyPackageVarsByPkg: lazyPackageVarsByPkg,
322
- tempNames: newTempNameOwner(),
323
- topLevel: true,
324
- protobufTSAdapter: protobufTypeScriptAdapter,
325
- displayRoot: displayRoot,
329
+ model: model,
330
+ semPkg: semPkg,
331
+ file: file,
332
+ importAliases: importAliases,
333
+ importPaths: importPaths,
334
+ importNames: importNames,
335
+ importObjects: importObjects,
336
+ sourcePath: sourcePath,
337
+ localAliases: localRefs.aliases,
338
+ lazyPackageVars: lazyPackageVars,
339
+ lazyPackageVarsByPkg: lazyPackageVarsByPkg,
340
+ asyncLazyFunctionCache: asyncLazyFunctionCache,
341
+ asyncLazyFunctionVisiting: asyncLazyFunctionVisiting,
342
+ tempNames: newTempNameOwner(),
343
+ topLevel: true,
344
+ protobufTSAdapter: protobufTypeScriptAdapter,
345
+ displayRoot: displayRoot,
326
346
  }
327
347
  var diagnostics []Diagnostic
328
348
  var packageInitCalls []string
@@ -1067,7 +1087,7 @@ func safeIdentifier(value string) string {
1067
1087
  switch identifier {
1068
1088
  case "abstract", "any", "arguments", "as", "asserts", "async", "await", "boolean",
1069
1089
  "break", "case", "catch", "class", "const", "constructor", "continue", "debugger",
1070
- "declare", "default", "delete", "do", "else", "enum", "export", "extends", "false",
1090
+ "declare", "default", "delete", "do", "else", "enum", "eval", "export", "extends", "false",
1071
1091
  "finally", "for", "from", "function", "get", "if", "implements", "import", "in",
1072
1092
  "infer", "instanceof", "interface", "is", "keyof", "let", "module", "namespace",
1073
1093
  "never", "new", "null", "number", "object", "of", "package", "private", "protected",
@@ -1095,40 +1115,42 @@ func safeParamName(param *types.Var, idx int) string {
1095
1115
  }
1096
1116
 
1097
1117
  type lowerFileContext struct {
1098
- model *SemanticModel
1099
- semPkg *semanticPackage
1100
- file *ast.File
1101
- importAliases map[string]string
1102
- importPaths map[string]string
1103
- importNames map[string]string
1104
- importObjects map[*types.PkgName]string
1105
- sourcePath string
1106
- localAliases map[types.Object]string
1107
- lazyPackageVars map[types.Object]bool
1108
- lazyPackageVarsByPkg map[string]map[types.Object]bool
1109
- identAliases map[types.Object]string
1110
- identAliasRefs map[types.Object]bool
1111
- tempNames *tempNameOwner
1112
- signature *types.Signature
1113
- typeParams map[string]bool
1114
- staticTypeParams map[string]bool
1115
- asyncFunction bool
1116
- functionTypeDepth int
1117
- deferState *loweredDeferState
1118
- rangeBranch *loweredRangeBranch
1119
- rangeBreak bool
1120
- rangeContinue bool
1121
- gotoLabels map[string]bool
1122
- forwardGotos map[string]bool
1123
- gotoStateLabels map[string]bool
1124
- gotoStateVar string
1125
- gotoStateLoop string
1126
- functionScopedDecls bool
1127
- loopLabel string
1128
- switchBreak bool
1129
- topLevel bool
1130
- protobufTSAdapter bool
1131
- displayRoot string
1118
+ model *SemanticModel
1119
+ semPkg *semanticPackage
1120
+ file *ast.File
1121
+ importAliases map[string]string
1122
+ importPaths map[string]string
1123
+ importNames map[string]string
1124
+ importObjects map[*types.PkgName]string
1125
+ sourcePath string
1126
+ localAliases map[types.Object]string
1127
+ lazyPackageVars map[types.Object]bool
1128
+ lazyPackageVarsByPkg map[string]map[types.Object]bool
1129
+ asyncLazyFunctionCache map[*types.Func]bool
1130
+ asyncLazyFunctionVisiting map[*types.Func]bool
1131
+ identAliases map[types.Object]string
1132
+ identAliasRefs map[types.Object]bool
1133
+ tempNames *tempNameOwner
1134
+ signature *types.Signature
1135
+ typeParams map[string]bool
1136
+ staticTypeParams map[string]bool
1137
+ asyncFunction bool
1138
+ functionTypeDepth int
1139
+ deferState *loweredDeferState
1140
+ rangeBranch *loweredRangeBranch
1141
+ rangeBreak bool
1142
+ rangeContinue bool
1143
+ gotoLabels map[string]bool
1144
+ forwardGotos map[string]bool
1145
+ gotoStateLabels map[string]bool
1146
+ gotoStateVar string
1147
+ gotoStateLoop string
1148
+ functionScopedDecls bool
1149
+ loopLabel string
1150
+ switchBreak bool
1151
+ topLevel bool
1152
+ protobufTSAdapter bool
1153
+ displayRoot string
1132
1154
  }
1133
1155
 
1134
1156
  func (ctx lowerFileContext) diagnosticPosition(pos token.Pos) *DiagnosticPosition {
@@ -1349,7 +1371,12 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
1349
1371
  "if (((" + declName + ") as any) === undefined) {\n\t\t" +
1350
1372
  declName + " = " + value + "\n\t}\n}"
1351
1373
  decls = append(decls, loweredDecl{code: initCode, indexExport: initIndexExport})
1352
- decls = append(decls, loweredDecl{packageInitCall: initName + "()"})
1374
+ readDrivenInit := idx < len(typed.Values) &&
1375
+ asyncLazyInitializerReferencesCyclicOtherFile(ctx, typed.Values[idx]) &&
1376
+ !packageInitFunctionReferencesObject(ctx, obj)
1377
+ if !readDrivenInit {
1378
+ decls = append(decls, loweredDecl{packageInitCall: initName + "()"})
1379
+ }
1353
1380
  getterCode += "if (((" + declName + ") as any) === undefined) {\n\t\t" +
1354
1381
  "throw new Error(" + strconv.Quote("goscript package variable "+name.Name+" read before initialization") + ")\n\t}\n"
1355
1382
  } else {
@@ -1409,21 +1436,33 @@ func (o *LoweringOwner) topLevelInitializerNeedsAwait(ctx lowerFileContext, expr
1409
1436
  if ctx.semPkg == nil || ctx.semPkg.source == nil {
1410
1437
  return false
1411
1438
  }
1412
- call, ok := unwrapParenExpr(expr).(*ast.CallExpr)
1413
- if !ok {
1414
- return false
1415
- }
1416
- if o.callNeedsAwait(ctx, call.Fun) {
1439
+ needsAwait := false
1440
+ ast.Inspect(expr, func(node ast.Node) bool {
1441
+ if needsAwait {
1442
+ return false
1443
+ }
1444
+ if _, ok := node.(*ast.FuncLit); ok {
1445
+ return false
1446
+ }
1447
+ call, ok := node.(*ast.CallExpr)
1448
+ if !ok {
1449
+ return true
1450
+ }
1451
+ if o.callNeedsAwait(ctx, call.Fun) {
1452
+ needsAwait = true
1453
+ return false
1454
+ }
1455
+ if o.callUsesOverridePackage(ctx, call.Fun) {
1456
+ return true
1457
+ }
1458
+ fn := calledFunction(ctx.semPkg.source, call.Fun)
1459
+ if fn != nil && fn.Pkg() != nil && fn.Pkg().Path() != ctx.semPkg.pkgPath {
1460
+ needsAwait = true
1461
+ return false
1462
+ }
1417
1463
  return true
1418
- }
1419
- if o.callUsesOverridePackage(ctx, call.Fun) {
1420
- return false
1421
- }
1422
- fn := calledFunction(ctx.semPkg.source, call.Fun)
1423
- if fn == nil || fn.Pkg() == nil || fn.Pkg().Path() == ctx.semPkg.pkgPath {
1424
- return false
1425
- }
1426
- return true
1464
+ })
1465
+ return needsAwait
1427
1466
  }
1428
1467
 
1429
1468
  func initializerMayHaveRuntimeEffects(ctx lowerFileContext, expr ast.Expr) bool {
@@ -1542,14 +1581,47 @@ func packageDeclFiles(semPkg *semanticPackage) map[types.Object]string {
1542
1581
  return nil
1543
1582
  }
1544
1583
  declFiles := make(map[types.Object]string, len(semPkg.declarations))
1584
+ for idx, file := range semPkg.source.Syntax {
1585
+ sourcePath := sourceFilePath(semPkg, idx, file)
1586
+ for _, decl := range file.Decls {
1587
+ recordDeclFileObjects(semPkg.source.TypesInfo, declFiles, sourcePath, decl)
1588
+ }
1589
+ }
1545
1590
  for _, decl := range semPkg.declarations {
1546
- if decl.object != nil && decl.position.file != "" {
1591
+ if decl.object != nil && decl.position.file != "" && declFiles[decl.object] == "" {
1547
1592
  declFiles[decl.object] = decl.position.file
1548
1593
  }
1549
1594
  }
1550
1595
  return declFiles
1551
1596
  }
1552
1597
 
1598
+ func recordDeclFileObjects(info *types.Info, declFiles map[types.Object]string, sourcePath string, decl ast.Decl) {
1599
+ if info == nil || sourcePath == "" {
1600
+ return
1601
+ }
1602
+ switch typed := decl.(type) {
1603
+ case *ast.FuncDecl:
1604
+ if obj := info.Defs[typed.Name]; obj != nil {
1605
+ declFiles[obj] = sourcePath
1606
+ }
1607
+ case *ast.GenDecl:
1608
+ for _, spec := range typed.Specs {
1609
+ switch typedSpec := spec.(type) {
1610
+ case *ast.TypeSpec:
1611
+ if obj := info.Defs[typedSpec.Name]; obj != nil {
1612
+ declFiles[obj] = sourcePath
1613
+ }
1614
+ case *ast.ValueSpec:
1615
+ for _, name := range typedSpec.Names {
1616
+ if obj := info.Defs[name]; obj != nil {
1617
+ declFiles[obj] = sourcePath
1618
+ }
1619
+ }
1620
+ }
1621
+ }
1622
+ }
1623
+ }
1624
+
1553
1625
  func packageOutputNames(semPkg *semanticPackage) map[string]string {
1554
1626
  if semPkg == nil || semPkg.source == nil {
1555
1627
  return nil
@@ -1624,6 +1696,11 @@ func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage, declFiles map[t
1624
1696
  lazy[obj] = true
1625
1697
  continue
1626
1698
  }
1699
+ if valueIdx < len(valueSpec.Values) &&
1700
+ initializerCallsFunctionReferencingOtherFileObject(semPkg, declFiles, sourcePath, valueSpec.Values[valueIdx]) {
1701
+ lazy[obj] = true
1702
+ continue
1703
+ }
1627
1704
  if valueIdx < len(valueSpec.Values) &&
1628
1705
  initializerCallsFunctionReferencingLaterPackageVar(semPkg, varOrder, obj, valueSpec.Values[valueIdx]) {
1629
1706
  lazy[obj] = true
@@ -1794,7 +1871,14 @@ func (o *LoweringOwner) packageVarNameHasAsyncLazyInit(ctx lowerFileContext, pkg
1794
1871
  if semPkg == nil || semPkg.source == nil {
1795
1872
  return false
1796
1873
  }
1797
- initCtx := lowerFileContext{model: ctx.model, semPkg: semPkg, topLevel: true}
1874
+ initCtx := lowerFileContext{
1875
+ model: ctx.model,
1876
+ semPkg: semPkg,
1877
+ lazyPackageVarsByPkg: ctx.lazyPackageVarsByPkg,
1878
+ asyncLazyFunctionCache: ctx.asyncLazyFunctionCache,
1879
+ asyncLazyFunctionVisiting: ctx.asyncLazyFunctionVisiting,
1880
+ topLevel: true,
1881
+ }
1798
1882
  for _, file := range semPkg.source.Syntax {
1799
1883
  for _, decl := range file.Decls {
1800
1884
  genDecl, ok := decl.(*ast.GenDecl)
@@ -1885,6 +1969,83 @@ func initializerCallsFunctionReferencingLaterPackageVar(
1885
1969
  return references
1886
1970
  }
1887
1971
 
1972
+ func asyncLazyInitializerReferencesCyclicOtherFile(ctx lowerFileContext, expr ast.Expr) bool {
1973
+ if ctx.semPkg == nil || ctx.semPkg.source == nil || expr == nil {
1974
+ return false
1975
+ }
1976
+ declFiles := packageDeclFiles(ctx.semPkg)
1977
+ for otherFile := range initializerReferencedOtherFiles(ctx.semPkg, declFiles, ctx.sourcePath, expr) {
1978
+ if fileRuntimeReferencesSourceFile(ctx.semPkg, declFiles, otherFile, ctx.sourcePath) {
1979
+ return true
1980
+ }
1981
+ }
1982
+ return false
1983
+ }
1984
+
1985
+ func packageInitFunctionReferencesObject(ctx lowerFileContext, obj types.Object) bool {
1986
+ if obj == nil || ctx.semPkg == nil || ctx.semPkg.source == nil {
1987
+ return false
1988
+ }
1989
+ references := false
1990
+ for _, file := range ctx.semPkg.source.Syntax {
1991
+ for _, decl := range file.Decls {
1992
+ fnDecl, ok := decl.(*ast.FuncDecl)
1993
+ if !ok || fnDecl.Recv != nil || fnDecl.Name == nil || fnDecl.Name.Name != "init" || fnDecl.Body == nil {
1994
+ continue
1995
+ }
1996
+ ast.Inspect(fnDecl.Body, func(node ast.Node) bool {
1997
+ if references {
1998
+ return false
1999
+ }
2000
+ if _, ok := node.(*ast.FuncLit); ok {
2001
+ return false
2002
+ }
2003
+ ident, ok := node.(*ast.Ident)
2004
+ if !ok {
2005
+ return true
2006
+ }
2007
+ if ctx.semPkg.source.TypesInfo.Uses[ident] == obj {
2008
+ references = true
2009
+ return false
2010
+ }
2011
+ return true
2012
+ })
2013
+ if references {
2014
+ return true
2015
+ }
2016
+ }
2017
+ }
2018
+ return false
2019
+ }
2020
+
2021
+ func initializerCallsFunctionReferencingOtherFileObject(
2022
+ semPkg *semanticPackage,
2023
+ declFiles map[types.Object]string,
2024
+ sourcePath string,
2025
+ expr ast.Expr,
2026
+ ) bool {
2027
+ references := false
2028
+ ast.Inspect(expr, func(node ast.Node) bool {
2029
+ if references {
2030
+ return false
2031
+ }
2032
+ call, ok := node.(*ast.CallExpr)
2033
+ if !ok {
2034
+ return true
2035
+ }
2036
+ fn := calledFunction(semPkg.source, call.Fun)
2037
+ if fn == nil || fn.Pkg() == nil || fn.Pkg().Path() != semPkg.pkgPath {
2038
+ return true
2039
+ }
2040
+ if functionReferencesOtherFileObject(semPkg, declFiles, sourcePath, fn, nil) {
2041
+ references = true
2042
+ return false
2043
+ }
2044
+ return true
2045
+ })
2046
+ return references
2047
+ }
2048
+
1888
2049
  func functionReferencesLaterPackageVar(
1889
2050
  semPkg *semanticPackage,
1890
2051
  varOrder map[types.Object]int,
@@ -1936,6 +2097,288 @@ func functionReferencesLaterPackageVar(
1936
2097
  return references
1937
2098
  }
1938
2099
 
2100
+ func initializerReferencedOtherFiles(
2101
+ semPkg *semanticPackage,
2102
+ declFiles map[types.Object]string,
2103
+ sourcePath string,
2104
+ expr ast.Expr,
2105
+ ) map[string]bool {
2106
+ refs := make(map[string]bool)
2107
+ ast.Inspect(expr, func(node ast.Node) bool {
2108
+ if _, ok := node.(*ast.FuncLit); ok {
2109
+ return false
2110
+ }
2111
+ collectOtherFileReferences(semPkg, declFiles, sourcePath, node, refs)
2112
+ call, ok := node.(*ast.CallExpr)
2113
+ if !ok {
2114
+ return true
2115
+ }
2116
+ fn := calledFunction(semPkg.source, call.Fun)
2117
+ if fn == nil || fn.Pkg() == nil || fn.Pkg().Path() != semPkg.pkgPath {
2118
+ return true
2119
+ }
2120
+ collectFunctionOtherFileReferences(semPkg, declFiles, sourcePath, fn, nil, refs)
2121
+ return true
2122
+ })
2123
+ return refs
2124
+ }
2125
+
2126
+ func collectFunctionOtherFileReferences(
2127
+ semPkg *semanticPackage,
2128
+ declFiles map[types.Object]string,
2129
+ sourcePath string,
2130
+ fn *types.Func,
2131
+ seen map[*types.Func]bool,
2132
+ refs map[string]bool,
2133
+ ) {
2134
+ if fn == nil {
2135
+ return
2136
+ }
2137
+ if seen == nil {
2138
+ seen = make(map[*types.Func]bool)
2139
+ }
2140
+ if seen[fn] {
2141
+ return
2142
+ }
2143
+ seen[fn] = true
2144
+ fnDecl := functionDeclForObject(semPkg, fn)
2145
+ if fnDecl == nil || fnDecl.Body == nil {
2146
+ return
2147
+ }
2148
+ ast.Inspect(fnDecl.Body, func(node ast.Node) bool {
2149
+ if _, ok := node.(*ast.FuncLit); ok {
2150
+ return false
2151
+ }
2152
+ collectOtherFileReferences(semPkg, declFiles, sourcePath, node, refs)
2153
+ if call, ok := node.(*ast.CallExpr); ok {
2154
+ called := calledFunction(semPkg.source, call.Fun)
2155
+ if called != nil && called.Pkg() != nil && called.Pkg().Path() == semPkg.pkgPath {
2156
+ collectFunctionOtherFileReferences(semPkg, declFiles, sourcePath, called, seen, refs)
2157
+ }
2158
+ }
2159
+ return true
2160
+ })
2161
+ }
2162
+
2163
+ func collectOtherFileReferences(
2164
+ semPkg *semanticPackage,
2165
+ declFiles map[types.Object]string,
2166
+ sourcePath string,
2167
+ node ast.Node,
2168
+ refs map[string]bool,
2169
+ ) {
2170
+ if node == nil {
2171
+ return
2172
+ }
2173
+ if lit, ok := node.(*ast.CompositeLit); ok {
2174
+ collectOtherFileTypeReferences(semPkg, declFiles, sourcePath, semPkg.source.TypesInfo.TypeOf(lit), refs, make(map[types.Type]bool))
2175
+ }
2176
+ switch typed := node.(type) {
2177
+ case *ast.Ident:
2178
+ collectOtherFileObjectReference(declFiles, sourcePath, semPkg.source.TypesInfo.Uses[typed], refs)
2179
+ case *ast.SelectorExpr:
2180
+ collectOtherFileObjectReference(declFiles, sourcePath, semPkg.source.TypesInfo.Uses[typed.Sel], refs)
2181
+ if selection := semPkg.source.TypesInfo.Selections[typed]; selection != nil {
2182
+ collectOtherFileObjectReference(declFiles, sourcePath, selection.Obj(), refs)
2183
+ }
2184
+ }
2185
+ }
2186
+
2187
+ func collectOtherFileObjectReference(
2188
+ declFiles map[types.Object]string,
2189
+ sourcePath string,
2190
+ obj types.Object,
2191
+ refs map[string]bool,
2192
+ ) {
2193
+ if obj == nil || obj.Pkg() == nil {
2194
+ return
2195
+ }
2196
+ if declFile := declFiles[obj]; declFile != "" && declFile != sourcePath {
2197
+ refs[declFile] = true
2198
+ }
2199
+ }
2200
+
2201
+ func collectOtherFileTypeReferences(
2202
+ semPkg *semanticPackage,
2203
+ declFiles map[types.Object]string,
2204
+ sourcePath string,
2205
+ typ types.Type,
2206
+ refs map[string]bool,
2207
+ seen map[types.Type]bool,
2208
+ ) {
2209
+ if typ == nil || seen[typ] {
2210
+ return
2211
+ }
2212
+ seen[typ] = true
2213
+ if named := namedStructType(typ); named != nil {
2214
+ collectOtherFileObjectReference(declFiles, sourcePath, named.Obj(), refs)
2215
+ }
2216
+ switch typed := types.Unalias(typ).Underlying().(type) {
2217
+ case *types.Array:
2218
+ collectOtherFileTypeReferences(semPkg, declFiles, sourcePath, typed.Elem(), refs, seen)
2219
+ case *types.Slice:
2220
+ collectOtherFileTypeReferences(semPkg, declFiles, sourcePath, typed.Elem(), refs, seen)
2221
+ case *types.Pointer:
2222
+ collectOtherFileTypeReferences(semPkg, declFiles, sourcePath, typed.Elem(), refs, seen)
2223
+ case *types.Map:
2224
+ collectOtherFileTypeReferences(semPkg, declFiles, sourcePath, typed.Key(), refs, seen)
2225
+ collectOtherFileTypeReferences(semPkg, declFiles, sourcePath, typed.Elem(), refs, seen)
2226
+ case *types.Struct:
2227
+ for field := range typed.Fields() {
2228
+ collectOtherFileTypeReferences(semPkg, declFiles, sourcePath, field.Type(), refs, seen)
2229
+ }
2230
+ }
2231
+ }
2232
+
2233
+ func fileRuntimeReferencesSourceFile(
2234
+ semPkg *semanticPackage,
2235
+ declFiles map[types.Object]string,
2236
+ filePath string,
2237
+ sourcePath string,
2238
+ ) bool {
2239
+ if semPkg == nil || semPkg.source == nil || filePath == "" || sourcePath == "" {
2240
+ return false
2241
+ }
2242
+ for idx, file := range semPkg.source.Syntax {
2243
+ if sourceFilePath(semPkg, idx, file) != filePath {
2244
+ continue
2245
+ }
2246
+ references := false
2247
+ ast.Inspect(file, func(node ast.Node) bool {
2248
+ if references {
2249
+ return false
2250
+ }
2251
+ if _, ok := node.(*ast.FuncLit); ok {
2252
+ return false
2253
+ }
2254
+ if lit, ok := node.(*ast.CompositeLit); ok &&
2255
+ typeReferencesSourceFile(semPkg, declFiles, lit, sourcePath) {
2256
+ references = true
2257
+ return false
2258
+ }
2259
+ if ident, ok := node.(*ast.Ident); ok &&
2260
+ valueIdentReferencesSourceFile(semPkg, declFiles, ident, sourcePath) {
2261
+ references = true
2262
+ return false
2263
+ }
2264
+ if selector, ok := node.(*ast.SelectorExpr); ok {
2265
+ if valueSelectorReferencesSourceFile(semPkg, declFiles, selector, sourcePath) {
2266
+ references = true
2267
+ return false
2268
+ }
2269
+ }
2270
+ if call, ok := node.(*ast.CallExpr); ok {
2271
+ called := calledFunction(semPkg.source, call.Fun)
2272
+ if called != nil && declFiles[called] == sourcePath {
2273
+ references = true
2274
+ return false
2275
+ }
2276
+ }
2277
+ return true
2278
+ })
2279
+ return references
2280
+ }
2281
+ return false
2282
+ }
2283
+
2284
+ func valueIdentReferencesSourceFile(
2285
+ semPkg *semanticPackage,
2286
+ declFiles map[types.Object]string,
2287
+ ident *ast.Ident,
2288
+ sourcePath string,
2289
+ ) bool {
2290
+ if tv, ok := semPkg.source.TypesInfo.Types[ident]; ok && !tv.IsValue() {
2291
+ return false
2292
+ }
2293
+ return declFiles[semPkg.source.TypesInfo.Uses[ident]] == sourcePath
2294
+ }
2295
+
2296
+ func valueSelectorReferencesSourceFile(
2297
+ semPkg *semanticPackage,
2298
+ declFiles map[types.Object]string,
2299
+ selector *ast.SelectorExpr,
2300
+ sourcePath string,
2301
+ ) bool {
2302
+ if tv, ok := semPkg.source.TypesInfo.Types[selector]; ok && !tv.IsValue() {
2303
+ return false
2304
+ }
2305
+ if declFiles[semPkg.source.TypesInfo.Uses[selector.Sel]] == sourcePath {
2306
+ return true
2307
+ }
2308
+ if selection := semPkg.source.TypesInfo.Selections[selector]; selection != nil {
2309
+ return declFiles[selection.Obj()] == sourcePath
2310
+ }
2311
+ return false
2312
+ }
2313
+
2314
+ func typeReferencesSourceFile(
2315
+ semPkg *semanticPackage,
2316
+ declFiles map[types.Object]string,
2317
+ expr ast.Expr,
2318
+ sourcePath string,
2319
+ ) bool {
2320
+ refs := make(map[string]bool)
2321
+ collectOtherFileTypeReferences(semPkg, declFiles, "", semPkg.source.TypesInfo.TypeOf(expr), refs, make(map[types.Type]bool))
2322
+ return refs[sourcePath]
2323
+ }
2324
+
2325
+ func functionReferencesOtherFileObject(
2326
+ semPkg *semanticPackage,
2327
+ declFiles map[types.Object]string,
2328
+ sourcePath string,
2329
+ fn *types.Func,
2330
+ seen map[*types.Func]bool,
2331
+ ) bool {
2332
+ if fn == nil {
2333
+ return false
2334
+ }
2335
+ if seen == nil {
2336
+ seen = make(map[*types.Func]bool)
2337
+ }
2338
+ if seen[fn] {
2339
+ return false
2340
+ }
2341
+ seen[fn] = true
2342
+ fnDecl := functionDeclForObject(semPkg, fn)
2343
+ if fnDecl == nil || fnDecl.Body == nil {
2344
+ return false
2345
+ }
2346
+ references := false
2347
+ ast.Inspect(fnDecl.Body, func(node ast.Node) bool {
2348
+ if references {
2349
+ return false
2350
+ }
2351
+ if _, ok := node.(*ast.FuncLit); ok {
2352
+ return false
2353
+ }
2354
+ if lit, ok := node.(*ast.CompositeLit); ok {
2355
+ if zeroValueReferencesOtherFileObject(semPkg, declFiles, sourcePath, semPkg.source.TypesInfo.TypeOf(lit)) {
2356
+ references = true
2357
+ return false
2358
+ }
2359
+ }
2360
+ if ident, ok := node.(*ast.Ident); ok {
2361
+ obj := semPkg.source.TypesInfo.Uses[ident]
2362
+ if obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == semPkg.pkgPath {
2363
+ if declFile := declFiles[obj]; declFile != "" && declFile != sourcePath {
2364
+ references = true
2365
+ return false
2366
+ }
2367
+ }
2368
+ }
2369
+ if call, ok := node.(*ast.CallExpr); ok {
2370
+ called := calledFunction(semPkg.source, call.Fun)
2371
+ if called != nil && called.Pkg() != nil && called.Pkg().Path() == semPkg.pkgPath &&
2372
+ functionReferencesOtherFileObject(semPkg, declFiles, sourcePath, called, seen) {
2373
+ references = true
2374
+ return false
2375
+ }
2376
+ }
2377
+ return true
2378
+ })
2379
+ return references
2380
+ }
2381
+
1939
2382
  func functionDeclForObject(semPkg *semanticPackage, fn *types.Func) *ast.FuncDecl {
1940
2383
  if semPkg == nil || semPkg.source == nil || fn == nil {
1941
2384
  return nil
@@ -1962,6 +2405,12 @@ func initializerReferencesOtherFileObject(
1962
2405
  if references {
1963
2406
  return false
1964
2407
  }
2408
+ if lit, ok := node.(*ast.CompositeLit); ok {
2409
+ if zeroValueReferencesOtherFileObject(semPkg, declFiles, sourcePath, semPkg.source.TypesInfo.TypeOf(lit)) {
2410
+ references = true
2411
+ return false
2412
+ }
2413
+ }
1965
2414
  ident, ok := node.(*ast.Ident)
1966
2415
  if !ok {
1967
2416
  return true
@@ -2237,7 +2686,7 @@ func (o *LoweringOwner) lowerGoEmbedFSValue(ctx lowerFileContext, diagPos token.
2237
2686
  entries = append(entries, "["+strconv.Quote(path)+", "+byteSliceLiteral(filesByPath[path])+"]")
2238
2687
  }
2239
2688
  builtinAlias := o.runtimeOwner.BuiltinImport().Alias
2240
- return builtinAlias + ".markAsStructValue(new " + embedAlias + ".FS(new Map<string, Uint8Array>([" + strings.Join(entries, ", ") + "])))", nil
2689
+ return builtinAlias + ".markAsStructValue(new " + embedAlias + ".FS(new globalThis.Map<string, Uint8Array>([" + strings.Join(entries, ", ") + "])))", nil
2241
2690
  }
2242
2691
 
2243
2692
  type goEmbedFile struct {
@@ -2639,7 +3088,10 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2639
3088
  }
2640
3089
 
2641
3090
  methodDecls := o.methodDeclsForType(ctx, semType.named)
2642
- explicitMethods := make(map[string]bool, len(methodDecls))
3091
+ explicitMethods := make(map[string]bool, len(methodDecls)+len(semType.fields))
3092
+ for _, field := range semType.fields {
3093
+ explicitMethods[field.name] = true
3094
+ }
2643
3095
  if len(methodDecls) != 0 {
2644
3096
  lowered.methods = make([]loweredFunction, 0, len(methodDecls))
2645
3097
  for _, methodDecl := range methodDecls {
@@ -3622,28 +4074,17 @@ func (o *LoweringOwner) lowerStmtListAfter(
3622
4074
  hasGoto := stmtListHasGoto(stmts)
3623
4075
  var gotoSpans map[string]int
3624
4076
  var gotoLabels map[string]bool
3625
- var forwardStarts map[int]forwardGotoLabelSpan
4077
+ var forwardSpans map[string]forwardGotoLabelSpan
3626
4078
  if hasGoto {
3627
4079
  gotoSpans = backwardGotoLabelSpans(stmts)
3628
4080
  gotoLabels = make(map[string]bool, len(gotoSpans))
3629
4081
  for label := range gotoSpans {
3630
4082
  gotoLabels[label] = true
3631
4083
  }
3632
- forwardSpans := forwardGotoLabelSpans(stmts, gotoSpans)
3633
- forwardStarts = make(map[int]forwardGotoLabelSpan, len(forwardSpans))
4084
+ forwardSpans = forwardGotoLabelSpans(stmts, gotoSpans)
3634
4085
  for label, span := range forwardSpans {
3635
4086
  span.label = label
3636
- group := forwardStarts[span.start]
3637
- if group.forwardLabels == nil {
3638
- group.forwardLabels = make(map[string]bool)
3639
- }
3640
- group.forwardLabels[label] = true
3641
- if group.label == "" || span.labelIdx > group.labelIdx {
3642
- group.label = span.label
3643
- group.start = span.start
3644
- group.labelIdx = span.labelIdx
3645
- }
3646
- forwardStarts[span.start] = group
4087
+ forwardSpans[label] = span
3647
4088
  }
3648
4089
  }
3649
4090
  for idx := 0; idx < len(stmts); idx++ {
@@ -3680,20 +4121,17 @@ func (o *LoweringOwner) lowerStmtListAfter(
3680
4121
  idx = span.endIdx
3681
4122
  continue
3682
4123
  }
3683
- if span, ok := forwardStarts[idx]; ok {
3684
- bodyStmts := stmts[idx:span.labelIdx]
3685
- body, bodyDiagnostics := o.lowerStmtListAfter(
3686
- ctx.withForwardGotos(span.forwardLabels),
3687
- bodyStmts,
4124
+ if group, ok := forwardGotoLabelGroupAt(idx, forwardSpans); ok {
4125
+ groupLowered, groupDiagnostics := o.lowerForwardGotoLabelGroup(
4126
+ ctx,
4127
+ stmts,
4128
+ group,
3688
4129
  prevEndLine,
4130
+ leading,
3689
4131
  )
3690
- diagnostics = append(diagnostics, bodyDiagnostics...)
3691
- block := loweredStmt{hasBlock: true, text: span.label + ":", children: body}
3692
- if len(leading) != 0 {
3693
- block.leading = append(leading, block.leading...)
3694
- }
3695
- lowered = append(lowered, block)
3696
- if labeled, ok := stmts[span.labelIdx].(*ast.LabeledStmt); ok {
4132
+ diagnostics = append(diagnostics, groupDiagnostics...)
4133
+ lowered = append(lowered, groupLowered...)
4134
+ if labeled, ok := stmts[group.labelIdx].(*ast.LabeledStmt); ok {
3697
4135
  labelLowered, labelDiagnostics := o.lowerStmt(ctx, labeled.Stmt)
3698
4136
  diagnostics = append(diagnostics, labelDiagnostics...)
3699
4137
  lowered = append(lowered, labelLowered...)
@@ -3701,7 +4139,7 @@ func (o *LoweringOwner) lowerStmtListAfter(
3701
4139
  prevEndLine = endLine
3702
4140
  }
3703
4141
  }
3704
- idx = span.labelIdx
4142
+ idx = group.labelIdx
3705
4143
  continue
3706
4144
  }
3707
4145
  if labeled, ok := stmt.(*ast.LabeledStmt); ok {
@@ -4033,12 +4471,105 @@ func (o *LoweringOwner) lowerBackwardGotoLoop(
4033
4471
  }
4034
4472
 
4035
4473
  type forwardGotoLabelSpan struct {
4036
- label string
4474
+ label string
4475
+ start int
4476
+ labelIdx int
4477
+ }
4478
+
4479
+ type forwardGotoLabelGroup struct {
4037
4480
  start int
4038
4481
  labelIdx int
4482
+ spans []forwardGotoLabelSpan
4039
4483
  forwardLabels map[string]bool
4040
4484
  }
4041
4485
 
4486
+ func forwardGotoLabelGroupAt(start int, spans map[string]forwardGotoLabelSpan) (forwardGotoLabelGroup, bool) {
4487
+ var included map[string]bool
4488
+ group := forwardGotoLabelGroup{start: start, labelIdx: -1}
4489
+ for label, span := range spans {
4490
+ if span.start != start {
4491
+ continue
4492
+ }
4493
+ if included == nil {
4494
+ included = make(map[string]bool)
4495
+ group.forwardLabels = make(map[string]bool)
4496
+ }
4497
+ included[label] = true
4498
+ group.spans = append(group.spans, span)
4499
+ group.forwardLabels[label] = true
4500
+ if span.labelIdx > group.labelIdx {
4501
+ group.labelIdx = span.labelIdx
4502
+ }
4503
+ }
4504
+ if len(group.spans) == 0 {
4505
+ return forwardGotoLabelGroup{}, false
4506
+ }
4507
+
4508
+ for {
4509
+ changed := false
4510
+ for label, span := range spans {
4511
+ if included[label] || span.start < start || span.start >= group.labelIdx {
4512
+ continue
4513
+ }
4514
+ included[label] = true
4515
+ group.spans = append(group.spans, span)
4516
+ group.forwardLabels[label] = true
4517
+ if span.labelIdx > group.labelIdx {
4518
+ group.labelIdx = span.labelIdx
4519
+ }
4520
+ changed = true
4521
+ }
4522
+ if !changed {
4523
+ break
4524
+ }
4525
+ }
4526
+
4527
+ slices.SortFunc(group.spans, func(a, b forwardGotoLabelSpan) int {
4528
+ if n := cmp.Compare(a.labelIdx, b.labelIdx); n != 0 {
4529
+ return n
4530
+ }
4531
+ return cmp.Compare(a.label, b.label)
4532
+ })
4533
+ return group, true
4534
+ }
4535
+
4536
+ func (o *LoweringOwner) lowerForwardGotoLabelGroup(
4537
+ ctx lowerFileContext,
4538
+ stmts []ast.Stmt,
4539
+ group forwardGotoLabelGroup,
4540
+ prevEndLine int,
4541
+ leading []string,
4542
+ ) ([]loweredStmt, []Diagnostic) {
4543
+ forwardCtx := ctx.withForwardGotos(group.forwardLabels)
4544
+ first := group.spans[0]
4545
+ body, diagnostics := o.lowerStmtListAfter(forwardCtx, stmts[group.start:first.labelIdx], prevEndLine)
4546
+ block := loweredStmt{hasBlock: true, text: first.label + ":", children: body}
4547
+
4548
+ for idx := 1; idx < len(group.spans); idx++ {
4549
+ prev := group.spans[idx-1]
4550
+ next := group.spans[idx]
4551
+ children := []loweredStmt{block}
4552
+ if labeled, ok := stmts[prev.labelIdx].(*ast.LabeledStmt); ok {
4553
+ segment := make([]ast.Stmt, 0, next.labelIdx-prev.labelIdx)
4554
+ segment = append(segment, labeled.Stmt)
4555
+ segment = append(segment, stmts[prev.labelIdx+1:next.labelIdx]...)
4556
+ segmentLowered, segmentDiagnostics := o.lowerStmtListAfter(
4557
+ forwardCtx,
4558
+ segment,
4559
+ sourceLine(ctx, labeled.Label.End()),
4560
+ )
4561
+ diagnostics = append(diagnostics, segmentDiagnostics...)
4562
+ children = append(children, segmentLowered...)
4563
+ }
4564
+ block = loweredStmt{hasBlock: true, text: next.label + ":", children: children}
4565
+ }
4566
+
4567
+ if len(leading) != 0 {
4568
+ block.leading = append(leading, block.leading...)
4569
+ }
4570
+ return []loweredStmt{block}, diagnostics
4571
+ }
4572
+
4042
4573
  type leadingGotoBackwardLoop struct {
4043
4574
  label string
4044
4575
  labelIdx int
@@ -4395,6 +4926,9 @@ func (o *LoweringOwner) lowerMapIndexUpdateStmts(
4395
4926
  mapExpr, mapDiagnostics := o.lowerExpr(ctx, index.X)
4396
4927
  keyExpr, keyDiagnostics := o.lowerExpr(ctx, index.Index)
4397
4928
  diagnostics := append(mapDiagnostics, keyDiagnostics...)
4929
+ if mapType, ok := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(index.X)).Underlying().(*types.Map); ok {
4930
+ keyExpr = o.lowerValueForTarget(ctx, index.Index, mapType.Key(), keyExpr)
4931
+ }
4398
4932
  if tok == token.ASSIGN {
4399
4933
  return []loweredStmt{{text: o.runtimeOwner.QualifiedHelper(RuntimeHelperMapSet) + "(" + mapExpr + ", " + keyExpr + ", " + right + ")"}}, diagnostics
4400
4934
  }
@@ -4802,6 +5336,11 @@ func (o *LoweringOwner) lowerShortDeclNewShadowAliases(
4802
5336
  func shortDeclShadowNonValueIdents(ctx lowerFileContext, expr ast.Expr) map[*ast.Ident]bool {
4803
5337
  idents := make(map[*ast.Ident]bool)
4804
5338
  ast.Inspect(expr, func(node ast.Node) bool {
5339
+ if ident, ok := node.(*ast.Ident); ok {
5340
+ if _, ok := ctx.semPkg.source.TypesInfo.Uses[ident].(*types.TypeName); ok {
5341
+ idents[ident] = true
5342
+ }
5343
+ }
4805
5344
  switch typed := node.(type) {
4806
5345
  case *ast.CallExpr:
4807
5346
  if ident, ok := typed.Fun.(*ast.Ident); ok {
@@ -6354,7 +6893,7 @@ func (o *LoweringOwner) lowerTypeSwitchStmt(ctx lowerFileContext, stmt *ast.Type
6354
6893
  func (o *LoweringOwner) tsTypeSwitchCaseTypeFor(ctx lowerFileContext, typ types.Type) string {
6355
6894
  if named, ok := types.Unalias(typ).(*types.Named); ok {
6356
6895
  if _, ok := named.Underlying().(*types.Interface); ok {
6357
- return o.tsNonNilTypeFor(ctx, named)
6896
+ return o.tsTypeFor(ctx, named)
6358
6897
  }
6359
6898
  }
6360
6899
  return o.tsTypeFor(ctx, typ)
@@ -6366,7 +6905,7 @@ func loweredStmtsUseVarRefName(stmts []loweredStmt, name string) bool {
6366
6905
  }
6367
6906
  needle := name + ".value"
6368
6907
  for _, stmt := range stmts {
6369
- if strings.Contains(stmt.text, needle) {
6908
+ if loweredStmtTextUsesVarRefName(stmt.text, needle) {
6370
6909
  return true
6371
6910
  }
6372
6911
  if loweredStmtsUseVarRefName(stmt.children, name) {
@@ -6393,6 +6932,38 @@ func loweredStmtsUseVarRefName(stmts []loweredStmt, name string) bool {
6393
6932
  return false
6394
6933
  }
6395
6934
 
6935
+ func loweredStmtTextUsesVarRefName(text, needle string) bool {
6936
+ offset := 0
6937
+ for {
6938
+ idx := strings.Index(text[offset:], needle)
6939
+ if idx < 0 {
6940
+ return false
6941
+ }
6942
+ start := offset + idx
6943
+ end := start + len(needle)
6944
+ if tsIdentifierBoundaryBefore(text, start) && tsIdentifierBoundaryAfter(text, end) {
6945
+ return true
6946
+ }
6947
+ offset = start + 1
6948
+ }
6949
+ }
6950
+
6951
+ func tsIdentifierBoundaryBefore(text string, idx int) bool {
6952
+ if idx == 0 {
6953
+ return true
6954
+ }
6955
+ prev := text[idx-1]
6956
+ return prev != '.' && !isTSIdentifierByte(prev)
6957
+ }
6958
+
6959
+ func tsIdentifierBoundaryAfter(text string, idx int) bool {
6960
+ return idx >= len(text) || !isTSIdentifierByte(text[idx])
6961
+ }
6962
+
6963
+ func isTSIdentifierByte(b byte) bool {
6964
+ return b == '$' || b == '_' || ('0' <= b && b <= '9') || ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z')
6965
+ }
6966
+
6396
6967
  func (o *LoweringOwner) lowerTypeSwitchAssign(ctx lowerFileContext, stmt ast.Stmt) (string, string, bool, []Diagnostic) {
6397
6968
  switch typed := stmt.(type) {
6398
6969
  case *ast.ExprStmt:
@@ -6847,11 +7418,47 @@ func isLegacyOctalLiteral(value string) bool {
6847
7418
  }
6848
7419
 
6849
7420
  func (o *LoweringOwner) lowerFuncLit(ctx lowerFileContext, lit *ast.FuncLit) (string, bool, []Diagnostic) {
7421
+ return o.lowerFuncLitWithAsyncCalls(ctx, lit, true)
7422
+ }
7423
+
7424
+ func (o *LoweringOwner) lowerFuncLitForTarget(
7425
+ ctx lowerFileContext,
7426
+ lit *ast.FuncLit,
7427
+ targetType types.Type,
7428
+ allowAsyncOverrideCallback bool,
7429
+ ) (string, bool, []Diagnostic) {
7430
+ allowAsyncCalls := true
7431
+ if !allowAsyncOverrideCallback && signatureForType(targetType) != nil {
7432
+ allowAsyncCalls = false
7433
+ }
7434
+ return o.lowerFuncLitWithAsyncCalls(ctx, lit, allowAsyncCalls)
7435
+ }
7436
+
7437
+ func (o *LoweringOwner) lowerFuncLitWithAsyncCalls(
7438
+ ctx lowerFileContext,
7439
+ lit *ast.FuncLit,
7440
+ allowAsyncCalls bool,
7441
+ ) (string, bool, []Diagnostic) {
7442
+ function, async, signature, diagnostics := o.lowerFuncLitArrowWithAsyncCalls(ctx, lit, allowAsyncCalls)
7443
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperFunctionValue) +
7444
+ "(" + function + ", " + o.runtimeFunctionTypeInfo(signature, "") + ")", async, diagnostics
7445
+ }
7446
+
7447
+ func (o *LoweringOwner) lowerFuncLitCallCallee(ctx lowerFileContext, lit *ast.FuncLit) (string, bool, []Diagnostic) {
7448
+ function, async, _, diagnostics := o.lowerFuncLitArrowWithAsyncCalls(ctx, lit, true)
7449
+ return function, async, diagnostics
7450
+ }
7451
+
7452
+ func (o *LoweringOwner) lowerFuncLitArrowWithAsyncCalls(
7453
+ ctx lowerFileContext,
7454
+ lit *ast.FuncLit,
7455
+ allowAsyncCalls bool,
7456
+ ) (string, bool, *types.Signature, []Diagnostic) {
6850
7457
  signature, _ := ctx.semPkg.source.TypesInfo.TypeOf(lit).(*types.Signature)
6851
7458
  deferState := &loweredDeferState{}
6852
7459
  bodyCtx := ctx.withSignature(signature).withAsyncFunction(false).withDeferState(deferState).withoutRangeBranch()
6853
7460
  asyncCompatibleParams := funcLiteralNeedsAsyncFunctionParamCalls(signature)
6854
- if asyncCompatibleParams || funcLiteralUsesAwaitableCall(ctx, lit) {
7461
+ if allowAsyncCalls && (asyncCompatibleParams || funcLiteralUsesAwaitableCall(ctx, lit)) {
6855
7462
  bodyCtx = bodyCtx.withAsyncFunction(true)
6856
7463
  }
6857
7464
  var params []loweredParam
@@ -6876,8 +7483,7 @@ func (o *LoweringOwner) lowerFuncLit(ctx lowerFileContext, lit *ast.FuncLit) (st
6876
7483
  function := prefix + "(" + renderLoweredParams(params) + "): " +
6877
7484
  asyncResultType(o.tsSignatureResultFor(ctx, signature), async) + " => {\n" +
6878
7485
  rendered.String() + "}"
6879
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperFunctionValue) +
6880
- "(" + function + ", " + o.runtimeFunctionTypeInfo(signature, "") + ")", async, diagnostics
7486
+ return function, async, signature, diagnostics
6881
7487
  }
6882
7488
 
6883
7489
  func renderLoweredParams(params []loweredParam) string {
@@ -6976,6 +7582,9 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
6976
7582
  return constValue
6977
7583
  }
6978
7584
  }
7585
+ if imported, ok := o.lowerImportedIdent(ctx, obj, value, raw); ok {
7586
+ return imported
7587
+ }
6979
7588
  if alias := ctx.localAliases[obj]; alias != "" {
6980
7589
  if ctx.lazyPackageVars[obj] {
6981
7590
  lazyValue := alias + "." + packageVarGetterName(value) + "()"
@@ -7008,6 +7617,29 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
7008
7617
  return value
7009
7618
  }
7010
7619
 
7620
+ func (o *LoweringOwner) lowerImportedIdent(ctx lowerFileContext, obj types.Object, value string, raw bool) (string, bool) {
7621
+ if obj == nil || obj.Pkg() == nil || ctx.semPkg == nil || obj.Pkg().Path() == ctx.semPkg.pkgPath {
7622
+ return "", false
7623
+ }
7624
+ alias := ctx.importPaths[obj.Pkg().Path()]
7625
+ if alias == "" {
7626
+ return "", false
7627
+ }
7628
+ qualified := alias + "." + value
7629
+ if varObj, ok := obj.(*types.Var); ok &&
7630
+ (o.packageVarIsLazy(ctx, varObj) || o.packageVarNameIsLazy(ctx, obj.Pkg().Path(), obj.Name())) {
7631
+ qualified = alias + "." + packageVarGetterName(value) + "()"
7632
+ if (ctx.asyncFunction || ctx.topLevel) &&
7633
+ o.packageVarNameHasAsyncLazyInit(ctx, obj.Pkg().Path(), obj.Name()) {
7634
+ qualified = "(await " + alias + "." + packageVarInitName(value) + "(), " + qualified + ")"
7635
+ }
7636
+ }
7637
+ if raw {
7638
+ return qualified, true
7639
+ }
7640
+ return o.lowerPackageVarReadValue(ctx, obj, qualified), true
7641
+ }
7642
+
7011
7643
  func (o *LoweringOwner) lowerPackageVarReadValue(ctx lowerFileContext, obj types.Object, value string) string {
7012
7644
  if obj == nil || ctx.model == nil || !ctx.model.needsVarRef[obj] {
7013
7645
  return value
@@ -7082,6 +7714,17 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
7082
7714
  }
7083
7715
 
7084
7716
  args, diagnostics := o.lowerCallArgs(ctx, expr, callTargetSignature(ctx, expr.Fun))
7717
+ if fun, ok := unwrapParenExpr(expr.Fun).(*ast.FuncLit); ok {
7718
+ callee, async, calleeDiagnostics := o.lowerFuncLitCallCallee(ctx, fun)
7719
+ call := "(" + callee + ")(" + strings.Join(args, ", ") + ")"
7720
+ if async {
7721
+ call = "await " + call
7722
+ if ctx.deferState != nil {
7723
+ ctx.deferState.async = true
7724
+ }
7725
+ }
7726
+ return call, append(diagnostics, calleeDiagnostics...)
7727
+ }
7085
7728
 
7086
7729
  switch fun := expr.Fun.(type) {
7087
7730
  case *ast.Ident:
@@ -7239,16 +7882,6 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
7239
7882
  ctx.deferState.async = true
7240
7883
  }
7241
7884
  return o.awaitCallIfNeeded(ctx, fun, call), append(diagnostics, calleeDiagnostics...)
7242
- case *ast.FuncLit:
7243
- callee, async, calleeDiagnostics := o.lowerFuncLit(ctx, fun)
7244
- call := "(" + callee + ")(" + strings.Join(args, ", ") + ")"
7245
- if async {
7246
- call = "await " + call
7247
- if ctx.deferState != nil {
7248
- ctx.deferState.async = true
7249
- }
7250
- }
7251
- return call, append(diagnostics, calleeDiagnostics...)
7252
7885
  default:
7253
7886
  if callTargetSignature(ctx, expr.Fun) != nil {
7254
7887
  callee, calleeDiagnostics := o.lowerExpr(ctx, expr.Fun)
@@ -7276,13 +7909,14 @@ func (o *LoweringOwner) lowerCallArgs(
7276
7909
  signature *types.Signature,
7277
7910
  ) ([]string, []Diagnostic) {
7278
7911
  overrideCall := o.callUsesOverridePackage(ctx, expr.Fun)
7912
+ allowAsyncOverrideCallback := !overrideCall || o.overrideCallNeedsAwait(ctx, expr.Fun)
7279
7913
  if args, diagnostics, ok := o.lowerTupleCallArgs(ctx, expr, signature, overrideCall); ok {
7280
7914
  return args, diagnostics
7281
7915
  }
7282
7916
  if signature != nil && signature.Variadic() && overrideCall && !isBuiltinCallTarget(ctx, expr.Fun) {
7283
7917
  params := signature.Params()
7284
7918
  if params == nil || params.Len() == 0 {
7285
- return o.lowerFixedCallArgs(ctx, expr.Args, signature, overrideCall)
7919
+ return o.lowerFixedCallArgs(ctx, expr.Args, signature, overrideCall, allowAsyncOverrideCallback)
7286
7920
  }
7287
7921
  fixedCount := params.Len() - 1
7288
7922
  targetType := params.At(fixedCount).Type()
@@ -7292,7 +7926,7 @@ func (o *LoweringOwner) lowerCallArgs(
7292
7926
  args := make([]string, 0, len(expr.Args))
7293
7927
  var diagnostics []Diagnostic
7294
7928
  for idx, arg := range expr.Args {
7295
- lowered, argDiagnostics := o.lowerExpr(ctx, arg)
7929
+ lowered, argDiagnostics := o.lowerCallArgExpr(ctx, arg, params.At(min(idx, fixedCount)).Type(), allowAsyncOverrideCallback)
7296
7930
  diagnostics = append(diagnostics, argDiagnostics...)
7297
7931
  if idx < fixedCount {
7298
7932
  lowered = o.lowerCallArgForTarget(ctx, arg, params.At(idx).Type(), lowered, overrideCall)
@@ -7309,11 +7943,11 @@ func (o *LoweringOwner) lowerCallArgs(
7309
7943
  if signature == nil || !signature.Variadic() ||
7310
7944
  isBuiltinCallTarget(ctx, expr.Fun) ||
7311
7945
  overrideCall {
7312
- return o.lowerFixedCallArgs(ctx, expr.Args, signature, overrideCall)
7946
+ return o.lowerFixedCallArgs(ctx, expr.Args, signature, overrideCall, allowAsyncOverrideCallback)
7313
7947
  }
7314
7948
  params := signature.Params()
7315
7949
  if params == nil || params.Len() == 0 {
7316
- return o.lowerFixedCallArgs(ctx, expr.Args, signature, overrideCall)
7950
+ return o.lowerFixedCallArgs(ctx, expr.Args, signature, overrideCall, allowAsyncOverrideCallback)
7317
7951
  }
7318
7952
 
7319
7953
  fixedCount := params.Len() - 1
@@ -7321,7 +7955,11 @@ func (o *LoweringOwner) lowerCallArgs(
7321
7955
  var variadicArgs []string
7322
7956
  var diagnostics []Diagnostic
7323
7957
  for idx, arg := range expr.Args {
7324
- lowered, argDiagnostics := o.lowerExpr(ctx, arg)
7958
+ targetType := params.At(fixedCount).Type()
7959
+ if idx < fixedCount {
7960
+ targetType = params.At(idx).Type()
7961
+ }
7962
+ lowered, argDiagnostics := o.lowerCallArgExpr(ctx, arg, targetType, allowAsyncOverrideCallback)
7325
7963
  diagnostics = append(diagnostics, argDiagnostics...)
7326
7964
  if idx < fixedCount {
7327
7965
  lowered = o.lowerCallArgForTarget(ctx, arg, params.At(idx).Type(), lowered, overrideCall)
@@ -7422,6 +8060,7 @@ func (o *LoweringOwner) lowerFixedCallArgs(
7422
8060
  exprs []ast.Expr,
7423
8061
  signature *types.Signature,
7424
8062
  overrideCall bool,
8063
+ allowAsyncOverrideCallback bool,
7425
8064
  ) ([]string, []Diagnostic) {
7426
8065
  var params *types.Tuple
7427
8066
  if signature != nil {
@@ -7430,7 +8069,11 @@ func (o *LoweringOwner) lowerFixedCallArgs(
7430
8069
  args := make([]string, 0, len(exprs))
7431
8070
  var diagnostics []Diagnostic
7432
8071
  for idx, expr := range exprs {
7433
- lowered, exprDiagnostics := o.lowerExpr(ctx, expr)
8072
+ var targetType types.Type
8073
+ if params != nil && idx < params.Len() {
8074
+ targetType = params.At(idx).Type()
8075
+ }
8076
+ lowered, exprDiagnostics := o.lowerCallArgExpr(ctx, expr, targetType, allowAsyncOverrideCallback)
7434
8077
  diagnostics = append(diagnostics, exprDiagnostics...)
7435
8078
  if params != nil && idx < params.Len() {
7436
8079
  lowered = o.lowerCallArgForTarget(ctx, expr, params.At(idx).Type(), lowered, overrideCall)
@@ -7440,6 +8083,19 @@ func (o *LoweringOwner) lowerFixedCallArgs(
7440
8083
  return args, diagnostics
7441
8084
  }
7442
8085
 
8086
+ func (o *LoweringOwner) lowerCallArgExpr(
8087
+ ctx lowerFileContext,
8088
+ expr ast.Expr,
8089
+ targetType types.Type,
8090
+ overrideCall bool,
8091
+ ) (string, []Diagnostic) {
8092
+ if lit, ok := ast.Unparen(expr).(*ast.FuncLit); ok && targetType != nil {
8093
+ value, _, diagnostics := o.lowerFuncLitForTarget(ctx, lit, targetType, overrideCall)
8094
+ return value, diagnostics
8095
+ }
8096
+ return o.lowerExpr(ctx, expr)
8097
+ }
8098
+
7443
8099
  func (o *LoweringOwner) lowerCallArgForTarget(
7444
8100
  ctx lowerFileContext,
7445
8101
  expr ast.Expr,
@@ -7636,6 +8292,11 @@ func (o *LoweringOwner) lowerConversionExpr(
7636
8292
  if value, addressDiagnostics, ok := o.lowerUnsafePointerIntegerExpr(ctx, expr.Args[0]); ok {
7637
8293
  return value, append(diagnostics, addressDiagnostics...)
7638
8294
  }
8295
+ if isUintptrType(targetType) {
8296
+ // Opaque unsafe pointers have no JS integer address; keep identity-only
8297
+ // uintptr round trips, such as the standard noescape xor-zero pattern, as pointer tokens.
8298
+ return "(" + value + " as any)", diagnostics
8299
+ }
7639
8300
  }
7640
8301
  if helper, addressDiagnostics, ok := o.lowerReflectHeaderPointerConversion(ctx, targetType, expr.Args[0]); ok {
7641
8302
  return helper, append(diagnostics, addressDiagnostics...)
@@ -7644,6 +8305,9 @@ func (o *LoweringOwner) lowerConversionExpr(
7644
8305
  return helper, append(diagnostics, addressDiagnostics...)
7645
8306
  }
7646
8307
  if isUnsafePointerType(targetType) {
8308
+ if value, identityDiagnostics, ok := o.lowerUnsafePointerIdentityExpr(ctx, expr.Args[0]); ok {
8309
+ return "(" + value + " as any)", append(diagnostics, identityDiagnostics...)
8310
+ }
7647
8311
  return "(" + value + " as any)", diagnostics
7648
8312
  }
7649
8313
  if isNilExpr(expr.Args[0]) && isPointerType(targetType) {
@@ -7794,6 +8458,12 @@ func (o *LoweringOwner) lowerWideIntegerBinaryExpr(ctx lowerFileContext, expr *a
7794
8458
  case token.AND:
7795
8459
  return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64And, RuntimeHelperInt64And)) + "(" + left + ", " + right + ")", true
7796
8460
  case token.XOR:
8461
+ if isZeroIntegerExpr(ctx, expr.Y) {
8462
+ return left, true
8463
+ }
8464
+ if isZeroIntegerExpr(ctx, expr.X) {
8465
+ return right, true
8466
+ }
7797
8467
  return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Xor, RuntimeHelperInt64Xor)) + "(" + left + ", " + right + ")", true
7798
8468
  case token.OR:
7799
8469
  shift, ok := wideLeftShiftExpr(ctx, expr.X)
@@ -7865,6 +8535,11 @@ func lowIntegerBits(ctx lowerFileContext, expr ast.Expr) (int, bool) {
7865
8535
  return integerBits(ctx.semPkg.source.TypesInfo.TypeOf(expr))
7866
8536
  }
7867
8537
 
8538
+ func isZeroIntegerExpr(ctx lowerFileContext, expr ast.Expr) bool {
8539
+ value := ctx.semPkg.source.TypesInfo.Types[unwrapParenExpr(expr)].Value
8540
+ return value != nil && value.Kind() == constant.Int && constant.Sign(value) == 0
8541
+ }
8542
+
7868
8543
  func shiftMultiplier(amount int) string {
7869
8544
  return "(2 ** " + strconv.Itoa(amount) + ")"
7870
8545
  }
@@ -8315,6 +8990,9 @@ func (o *LoweringOwner) lowerFieldSelectionExpr(
8315
8990
  selection *types.Selection,
8316
8991
  address bool,
8317
8992
  ) (string, []Diagnostic) {
8993
+ if value, diagnostics, ok := o.lowerUnsafeStructFieldSelectionExpr(ctx, expr, selection, address); ok {
8994
+ return value, diagnostics
8995
+ }
8318
8996
  receiver, diagnostics := o.lowerFieldReceiverExpr(ctx, expr.X)
8319
8997
  receiver = parenthesizeAwaitedExpr(receiver)
8320
8998
  index := selection.Index()
@@ -8353,18 +9031,89 @@ func (o *LoweringOwner) lowerFieldSelectionExpr(
8353
9031
  typ = pointer.Elem()
8354
9032
  }
8355
9033
  }
8356
-
9034
+
9035
+ if address {
9036
+ return o.lowerFieldAddressExpr(ctx, receiver, typ, tsStructFieldName(expr.Sel.Name, 0)), diagnostics
9037
+ }
9038
+ return receiver + "." + tsStructFieldName(expr.Sel.Name, 0), diagnostics
9039
+ }
9040
+
9041
+ func (o *LoweringOwner) lowerFieldAddressExpr(ctx lowerFileContext, receiver string, typ types.Type, fieldName string) string {
9042
+ if namedStructType(derefPointerType(typ)) != nil {
9043
+ return receiver + "._fields." + fieldName
9044
+ }
9045
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperFieldRef) + "(" + receiver + ", " + strconv.Quote(fieldName) + ")"
9046
+ }
9047
+
9048
+ func (o *LoweringOwner) lowerUnsafeStructFieldSelectionExpr(
9049
+ ctx lowerFileContext,
9050
+ expr *ast.SelectorExpr,
9051
+ selection *types.Selection,
9052
+ address bool,
9053
+ ) (string, []Diagnostic, bool) {
9054
+ index := selection.Index()
9055
+ if len(index) != 1 {
9056
+ return "", nil, false
9057
+ }
9058
+ targetCall, ok := unwrapParenExpr(expr.X).(*ast.CallExpr)
9059
+ if !ok || len(targetCall.Args) != 1 {
9060
+ return "", nil, false
9061
+ }
9062
+ targetType := typeFromExpr(ctx, targetCall.Fun)
9063
+ if targetType == nil {
9064
+ return "", nil, false
9065
+ }
9066
+ targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
9067
+ if targetPointer == nil {
9068
+ return "", nil, false
9069
+ }
9070
+ targetStruct := structUnderlyingType(targetPointer.Elem())
9071
+ if targetStruct == nil || index[0] < 0 || index[0] >= targetStruct.NumFields() {
9072
+ return "", nil, false
9073
+ }
9074
+ unsafeCall, ok := unwrapParenExpr(targetCall.Args[0]).(*ast.CallExpr)
9075
+ if !ok || len(unsafeCall.Args) != 1 || !isUnsafePointerType(typeFromExpr(ctx, unsafeCall.Fun)) {
9076
+ return "", nil, false
9077
+ }
9078
+ sourceType := ctx.semPkg.source.TypesInfo.TypeOf(unsafeCall.Args[0])
9079
+ if sourceType == nil {
9080
+ return "", nil, false
9081
+ }
9082
+ sourcePointer, _ := types.Unalias(sourceType).Underlying().(*types.Pointer)
9083
+ if sourcePointer == nil {
9084
+ return "", nil, false
9085
+ }
9086
+ sourceStruct := structUnderlyingType(sourcePointer.Elem())
9087
+ if sourceStruct == nil || index[0] >= sourceStruct.NumFields() {
9088
+ return "", nil, false
9089
+ }
9090
+ targetField := targetStruct.Field(index[0])
9091
+ sourceField := sourceStruct.Field(index[0])
9092
+ if !unsafeStructFieldLayoutCompatible(targetField, sourceField) {
9093
+ return "", nil, false
9094
+ }
9095
+ receiver, diagnostics := o.lowerFieldReceiverExpr(ctx, unsafeCall.Args[0])
9096
+ fieldName := tsStructFieldName(sourceField.Name(), index[0])
8357
9097
  if address {
8358
- return o.lowerFieldAddressExpr(ctx, receiver, typ, tsStructFieldName(expr.Sel.Name, 0)), diagnostics
9098
+ return o.lowerFieldAddressExpr(ctx, receiver, sourcePointer.Elem(), fieldName), diagnostics, true
8359
9099
  }
8360
- return receiver + "." + tsStructFieldName(expr.Sel.Name, 0), diagnostics
9100
+ return receiver + "." + fieldName, diagnostics, true
8361
9101
  }
8362
9102
 
8363
- func (o *LoweringOwner) lowerFieldAddressExpr(ctx lowerFileContext, receiver string, typ types.Type, fieldName string) string {
8364
- if namedStructType(derefPointerType(typ)) != nil {
8365
- return receiver + "._fields." + fieldName
9103
+ func unsafeStructFieldLayoutCompatible(target *types.Var, source *types.Var) bool {
9104
+ if target == nil || source == nil || target.Name() != source.Name() {
9105
+ return false
8366
9106
  }
8367
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperFieldRef) + "(" + receiver + ", " + strconv.Quote(fieldName) + ")"
9107
+ return unsafeFieldTypeLayoutCompatible(target.Type(), source.Type())
9108
+ }
9109
+
9110
+ func unsafeFieldTypeLayoutCompatible(left types.Type, right types.Type) bool {
9111
+ if types.Identical(left, right) {
9112
+ return true
9113
+ }
9114
+ leftUnderlying := types.Unalias(left).Underlying()
9115
+ rightUnderlying := types.Unalias(right).Underlying()
9116
+ return types.Identical(leftUnderlying, rightUnderlying)
8368
9117
  }
8369
9118
 
8370
9119
  func (o *LoweringOwner) lowerMethodValueClosure(
@@ -8390,7 +9139,12 @@ func (o *LoweringOwner) lowerMethodValueClosure(
8390
9139
  if includeReceiver {
8391
9140
  args = append([]string{"__receiver"}, args...)
8392
9141
  }
8393
- return "((__receiver) => (" + strings.Join(params, ", ") + ") => " + callee + "(" + strings.Join(args, ", ") + "))(" + receiver + ")"
9142
+ closure := "((__receiver) => (" + strings.Join(params, ", ") + ") => " + callee + "(" + strings.Join(args, ", ") + "))(" + receiver + ")"
9143
+ if signature == nil {
9144
+ return closure
9145
+ }
9146
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperFunctionValue) +
9147
+ "(" + closure + ", " + o.runtimeFunctionTypeInfo(signature, "") + ")"
8394
9148
  }
8395
9149
 
8396
9150
  func (o *LoweringOwner) lowerMethodExpressionClosure(ctx lowerFileContext, selection *types.Selection) string {
@@ -8445,6 +9199,9 @@ func fieldReceiverNeedsVarRefValue(ctx lowerFileContext, expr ast.Expr, obj type
8445
9199
  return true
8446
9200
  }
8447
9201
  if ctx.identAliases[obj] != "" {
9202
+ if obj == nil || ctx.model == nil || !ctx.model.needsVarRef[obj] {
9203
+ return false
9204
+ }
8448
9205
  return !ctx.identAliasRefs[obj]
8449
9206
  }
8450
9207
  if ctx.localAliases[obj] != "" {
@@ -8605,6 +9362,10 @@ func (o *LoweringOwner) lowerAddressExpr(ctx lowerFileContext, expr ast.Expr) (s
8605
9362
  return receiver + "._fields." + typed.Sel.Name, diagnostics
8606
9363
  case *ast.IndexExpr:
8607
9364
  return o.lowerIndexAddressExpr(ctx, typed)
9365
+ case *ast.StarExpr:
9366
+ // &*p is the identity address-of-dereference: it yields the original
9367
+ // pointer, not a copy, so emit the pointer expression directly.
9368
+ return o.lowerExpr(ctx, typed.X)
8608
9369
  default:
8609
9370
  return "undefined", []Diagnostic{loweringUnsupportedAt(ctx, typed, "expression", ctx.semPkg.pkgPath, "unsupported address expression")}
8610
9371
  }
@@ -8696,6 +9457,35 @@ func (o *LoweringOwner) lowerUnsafePointerIntegerExpr(
8696
9457
  return o.lowerIndexByteAddressIntegerExpr(ctx, call.Args[0])
8697
9458
  }
8698
9459
 
9460
+ func (o *LoweringOwner) lowerUnsafePointerIdentityExpr(
9461
+ ctx lowerFileContext,
9462
+ expr ast.Expr,
9463
+ ) (string, []Diagnostic, bool) {
9464
+ expr = unwrapParenExpr(expr)
9465
+ if binary, ok := expr.(*ast.BinaryExpr); ok && binary.Op == token.XOR {
9466
+ switch {
9467
+ case isZeroIntegerExpr(ctx, binary.Y):
9468
+ return o.lowerUnsafePointerIdentityExpr(ctx, binary.X)
9469
+ case isZeroIntegerExpr(ctx, binary.X):
9470
+ return o.lowerUnsafePointerIdentityExpr(ctx, binary.Y)
9471
+ }
9472
+ }
9473
+ call, ok := expr.(*ast.CallExpr)
9474
+ if !ok || len(call.Args) != 1 {
9475
+ return "", nil, false
9476
+ }
9477
+ targetType := typeFromExpr(ctx, call.Fun)
9478
+ sourceType := ctx.semPkg.source.TypesInfo.TypeOf(call.Args[0])
9479
+ if !isUintptrType(targetType) || !isUnsafePointerType(sourceType) {
9480
+ return "", nil, false
9481
+ }
9482
+ if _, _, ok := o.lowerUnsafePointerIntegerExpr(ctx, call.Args[0]); ok {
9483
+ return "", nil, false
9484
+ }
9485
+ value, diagnostics := o.lowerExpr(ctx, call.Args[0])
9486
+ return value, diagnostics, true
9487
+ }
9488
+
8699
9489
  func (o *LoweringOwner) lowerIndexAddressIntegerExpr(
8700
9490
  ctx lowerFileContext,
8701
9491
  expr ast.Expr,
@@ -8866,6 +9656,9 @@ func (o *LoweringOwner) lowerUnsafeArrayPointerConversion(
8866
9656
  targetType types.Type,
8867
9657
  expr ast.Expr,
8868
9658
  ) (string, []Diagnostic, bool) {
9659
+ if targetType == nil {
9660
+ return "", nil, false
9661
+ }
8869
9662
  targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
8870
9663
  if targetPointer == nil {
8871
9664
  return "", nil, false
@@ -8874,29 +9667,191 @@ func (o *LoweringOwner) lowerUnsafeArrayPointerConversion(
8874
9667
  if array == nil {
8875
9668
  return "", nil, false
8876
9669
  }
8877
- unsafeCall, ok := unwrapParenExpr(expr).(*ast.CallExpr)
8878
- if !ok || len(unsafeCall.Args) != 1 || !isUnsafePointerType(typeFromExpr(ctx, unsafeCall.Fun)) {
8879
- return "", nil, false
8880
- }
8881
- address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
8882
- if !ok || address.Op != token.AND {
8883
- return "", nil, false
8884
- }
8885
- index, ok := unwrapParenExpr(address.X).(*ast.IndexExpr)
9670
+ ref, sourceType, diagnostics, ok := o.lowerUnsafeArrayPointerSourceRef(ctx, expr)
8886
9671
  if !ok {
8887
9672
  return "", nil, false
8888
9673
  }
8889
- ref, diagnostics := o.lowerAddressExpr(ctx, index)
8890
- sourceElementSize := goScriptElementByteSize(ctx, indexElementType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)))
9674
+ sourceElementSize := goScriptElementByteSize(ctx, sourceType)
8891
9675
  targetElementSize := goScriptElementByteSize(ctx, array.Elem())
9676
+ sourceTypeArg := o.tsTypeFor(ctx, array.Elem())
9677
+ if sourceType != nil {
9678
+ sourceTypeArg = o.tsTypeFor(ctx, sourceType)
9679
+ }
8892
9680
  helper := o.runtimeOwner.QualifiedHelper(RuntimeHelperArrayPointerFromIndexRef) +
8893
- "<" + o.tsTypeFor(ctx, array.Elem()) + ">(" + ref + ", " +
9681
+ "<" + sourceTypeArg + ">(" + ref + ", " +
8894
9682
  strconv.FormatInt(array.Len(), 10) + ", " +
8895
9683
  strconv.FormatInt(sourceElementSize, 10) + ", " +
8896
9684
  strconv.FormatInt(targetElementSize, 10) + ")"
8897
9685
  return "(" + helper + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics, true
8898
9686
  }
8899
9687
 
9688
+ func (o *LoweringOwner) lowerUnsafeArrayPointerSourceRef(
9689
+ ctx lowerFileContext,
9690
+ expr ast.Expr,
9691
+ ) (string, types.Type, []Diagnostic, bool) {
9692
+ if unsafeCall, ok := unwrapParenExpr(expr).(*ast.CallExpr); ok && len(unsafeCall.Args) == 1 {
9693
+ if isUnsafePointerType(typeFromExpr(ctx, unsafeCall.Fun)) {
9694
+ return o.lowerUnsafeArrayPointerAddressSourceRef(ctx, unsafeCall.Args[0])
9695
+ }
9696
+ if arg, ok := unsafePointerIdentityCallArg(ctx, unsafeCall); ok {
9697
+ return o.lowerUnsafeArrayPointerSourceRef(ctx, arg)
9698
+ }
9699
+ }
9700
+ return o.lowerUnsafeArrayPointerAddressSourceRef(ctx, expr)
9701
+ }
9702
+
9703
+ func (o *LoweringOwner) lowerUnsafeArrayPointerAddressSourceRef(
9704
+ ctx lowerFileContext,
9705
+ expr ast.Expr,
9706
+ ) (string, types.Type, []Diagnostic, bool) {
9707
+ if source, ok := stringHeaderDataSource(ctx, expr); ok {
9708
+ value, diagnostics := o.lowerExpr(ctx, source)
9709
+ bytes := o.runtimeOwner.QualifiedHelper(RuntimeHelperStringToBytes) + "(" + value + ")"
9710
+ ref := o.runtimeOwner.QualifiedHelper(RuntimeHelperIndexRef) + "(" + bytes + ", 0)"
9711
+ return ref, types.Typ[types.Uint8], diagnostics, true
9712
+ }
9713
+
9714
+ address, ok := unwrapParenExpr(expr).(*ast.UnaryExpr)
9715
+ if !ok || address.Op != token.AND {
9716
+ return "", nil, nil, false
9717
+ }
9718
+ if index, ok := unwrapParenExpr(address.X).(*ast.IndexExpr); ok {
9719
+ ref, diagnostics := o.lowerAddressExpr(ctx, index)
9720
+ return ref, indexElementType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)), diagnostics, true
9721
+ }
9722
+ sourceType := ctx.semPkg.source.TypesInfo.TypeOf(address.X)
9723
+ if isNumericType(sourceType) || isStringType(sourceType) || isComplexType(sourceType) {
9724
+ value, diagnostics := o.lowerExpr(ctx, address.X)
9725
+ ref := o.runtimeOwner.QualifiedHelper(RuntimeHelperIndexRef) + "([" + value + "], 0)"
9726
+ return ref, sourceType, diagnostics, true
9727
+ }
9728
+ ref, diagnostics := o.lowerAddressExpr(ctx, address.X)
9729
+ return ref, sourceType, diagnostics, true
9730
+ }
9731
+
9732
+ func unsafePointerIdentityCallArg(ctx lowerFileContext, call *ast.CallExpr) (ast.Expr, bool) {
9733
+ if call == nil || len(call.Args) != 1 ||
9734
+ !isUnsafePointerType(ctx.semPkg.source.TypesInfo.TypeOf(call)) ||
9735
+ !isUnsafePointerType(ctx.semPkg.source.TypesInfo.TypeOf(call.Args[0])) {
9736
+ return nil, false
9737
+ }
9738
+ fn := calledFunction(ctx.semPkg.source, call.Fun)
9739
+ decl := functionDeclForObject(ctx.semPkg, fn)
9740
+ if decl == nil || decl.Type == nil || decl.Type.Params == nil ||
9741
+ len(decl.Type.Params.List) != 1 || len(decl.Type.Params.List[0].Names) != 1 ||
9742
+ decl.Body == nil {
9743
+ return nil, false
9744
+ }
9745
+ param := objectForIdent(ctx, decl.Type.Params.List[0].Names[0])
9746
+ if param == nil {
9747
+ return nil, false
9748
+ }
9749
+ aliases := make(map[types.Object]bool)
9750
+ for _, stmt := range decl.Body.List {
9751
+ switch typed := stmt.(type) {
9752
+ case *ast.AssignStmt:
9753
+ if !recordUnsafePointerUintptrAlias(ctx, typed, param, aliases) {
9754
+ return nil, false
9755
+ }
9756
+ case *ast.ReturnStmt:
9757
+ if len(typed.Results) == 1 && unsafePointerIdentityReturnExpr(ctx, typed.Results[0], param, aliases) {
9758
+ return call.Args[0], true
9759
+ }
9760
+ return nil, false
9761
+ default:
9762
+ return nil, false
9763
+ }
9764
+ }
9765
+ return nil, false
9766
+ }
9767
+
9768
+ func recordUnsafePointerUintptrAlias(ctx lowerFileContext, stmt *ast.AssignStmt, param types.Object, aliases map[types.Object]bool) bool {
9769
+ if stmt == nil || len(stmt.Lhs) != 1 || len(stmt.Rhs) != 1 {
9770
+ return false
9771
+ }
9772
+ ident, ok := unwrapParenExpr(stmt.Lhs[0]).(*ast.Ident)
9773
+ if !ok || ident.Name == "_" {
9774
+ return false
9775
+ }
9776
+ if !unsafePointerUintptrIdentityExpr(ctx, stmt.Rhs[0], param, aliases) {
9777
+ return false
9778
+ }
9779
+ obj := objectForIdent(ctx, ident)
9780
+ if obj == nil {
9781
+ return false
9782
+ }
9783
+ aliases[obj] = true
9784
+ return true
9785
+ }
9786
+
9787
+ func unsafePointerIdentityReturnExpr(ctx lowerFileContext, expr ast.Expr, param types.Object, aliases map[types.Object]bool) bool {
9788
+ expr = unwrapParenExpr(expr)
9789
+ if ident, ok := expr.(*ast.Ident); ok {
9790
+ return objectForIdent(ctx, ident) == param
9791
+ }
9792
+ call, ok := expr.(*ast.CallExpr)
9793
+ if !ok || len(call.Args) != 1 || !isUnsafePointerType(typeFromExpr(ctx, call.Fun)) {
9794
+ return false
9795
+ }
9796
+ return unsafePointerUintptrIdentityExpr(ctx, call.Args[0], param, aliases)
9797
+ }
9798
+
9799
+ func unsafePointerUintptrIdentityExpr(ctx lowerFileContext, expr ast.Expr, param types.Object, aliases map[types.Object]bool) bool {
9800
+ expr = unwrapParenExpr(expr)
9801
+ if binary, ok := expr.(*ast.BinaryExpr); ok && binary.Op == token.XOR {
9802
+ switch {
9803
+ case isZeroIntegerExpr(ctx, binary.Y):
9804
+ return unsafePointerUintptrIdentityExpr(ctx, binary.X, param, aliases)
9805
+ case isZeroIntegerExpr(ctx, binary.X):
9806
+ return unsafePointerUintptrIdentityExpr(ctx, binary.Y, param, aliases)
9807
+ }
9808
+ return false
9809
+ }
9810
+ if ident, ok := expr.(*ast.Ident); ok {
9811
+ obj := objectForIdent(ctx, ident)
9812
+ return obj == param || aliases[obj]
9813
+ }
9814
+ call, ok := expr.(*ast.CallExpr)
9815
+ if !ok || len(call.Args) != 1 || !isUintptrType(typeFromExpr(ctx, call.Fun)) {
9816
+ return false
9817
+ }
9818
+ ident, ok := unwrapParenExpr(call.Args[0]).(*ast.Ident)
9819
+ return ok && objectForIdent(ctx, ident) == param
9820
+ }
9821
+
9822
+ func stringHeaderDataSource(ctx lowerFileContext, expr ast.Expr) (ast.Expr, bool) {
9823
+ selector, ok := unwrapParenExpr(expr).(*ast.SelectorExpr)
9824
+ if !ok || selector.Sel.Name != "Data" {
9825
+ return nil, false
9826
+ }
9827
+ call, ok := unwrapParenExpr(selector.X).(*ast.CallExpr)
9828
+ if !ok || len(call.Args) != 1 {
9829
+ return nil, false
9830
+ }
9831
+ targetType := typeFromExpr(ctx, call.Fun)
9832
+ if targetType == nil {
9833
+ return nil, false
9834
+ }
9835
+ targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
9836
+ if targetPointer == nil {
9837
+ return nil, false
9838
+ }
9839
+ header, _ := types.Unalias(targetPointer.Elem()).(*types.Named)
9840
+ if header == nil || header.Obj() == nil || header.Obj().Pkg() == nil ||
9841
+ header.Obj().Pkg().Path() != "reflect" || header.Obj().Name() != "StringHeader" {
9842
+ return nil, false
9843
+ }
9844
+ unsafeCall, ok := unwrapParenExpr(call.Args[0]).(*ast.CallExpr)
9845
+ if !ok || len(unsafeCall.Args) != 1 || !isUnsafePointerType(typeFromExpr(ctx, unsafeCall.Fun)) {
9846
+ return nil, false
9847
+ }
9848
+ address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
9849
+ if !ok || address.Op != token.AND || !isStringType(ctx.semPkg.source.TypesInfo.TypeOf(address.X)) {
9850
+ return nil, false
9851
+ }
9852
+ return address.X, true
9853
+ }
9854
+
8900
9855
  func (o *LoweringOwner) lowerAddressedValueRef(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
8901
9856
  if ident, ok := unwrapParenExpr(expr).(*ast.Ident); ok {
8902
9857
  if obj := objectForIdent(ctx, ident); obj != nil && ctx.model.needsVarRef[obj] {
@@ -9474,7 +10429,11 @@ func (o *LoweringOwner) lowerMapCompositeLit(
9474
10429
  value = o.lowerValueForTarget(ctx, keyed.Value, mapType.Elem(), value)
9475
10430
  entries = append(entries, "["+key+", "+value+"]")
9476
10431
  }
9477
- return "new Map<" + o.tsTypeFor(ctx, mapType.Key()) + ", " + o.tsTypeFor(ctx, mapType.Elem()) + ">([" + strings.Join(entries, ", ") + "])", diagnostics
10432
+ return "new " + tsNativeMapType(o.tsTypeFor(ctx, mapType.Key()), o.tsTypeFor(ctx, mapType.Elem())) + "([" + strings.Join(entries, ", ") + "])", diagnostics
10433
+ }
10434
+
10435
+ func tsNativeMapType(keyType, elemType string) string {
10436
+ return "globalThis.Map<" + keyType + ", " + elemType + ">"
9478
10437
  }
9479
10438
 
9480
10439
  func (o *LoweringOwner) lowerTypeAssertExpr(ctx lowerFileContext, expr *ast.TypeAssertExpr) (string, []Diagnostic) {
@@ -9511,7 +10470,11 @@ func (o *LoweringOwner) lowerMapGetTuple(ctx lowerFileContext, expr *ast.IndexEx
9511
10470
  mapType, _ := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(expr.X)).Underlying().(*types.Map)
9512
10471
  defaultValue := "undefined"
9513
10472
  if mapType != nil {
10473
+ index = o.lowerValueForTarget(ctx, expr.Index, mapType.Key(), index)
9514
10474
  defaultValue = o.lowerZeroValueExprFor(ctx, mapType.Elem())
10475
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperMapGet) +
10476
+ "<" + o.tsTypeFor(ctx, mapType.Key()) + ", " + o.tsTypeFor(ctx, mapType.Elem()) + ", " + o.tsTypeFor(ctx, mapType.Elem()) + ">(" +
10477
+ target + ", " + index + ", " + defaultValue + ")"
9515
10478
  }
9516
10479
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperMapGet) + "(" + target + ", " + index + ", " + defaultValue + ")"
9517
10480
  }
@@ -10401,7 +11364,7 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
10401
11364
  case *types.Slice:
10402
11365
  return "$.Slice<" + o.tsSliceElemTypeFor(ctx, typed.Elem()) + ">"
10403
11366
  case *types.Map:
10404
- return "Map<" + o.tsTypeFor(ctx, typed.Key()) + ", " + o.tsTypeFor(ctx, typed.Elem()) + "> | null"
11367
+ return tsNativeMapType(o.tsTypeFor(ctx, typed.Key()), o.tsTypeFor(ctx, typed.Elem())) + " | null"
10405
11368
  case *types.Chan:
10406
11369
  return "$.Channel<" + o.tsTypeFor(ctx, typed.Elem()) + "> | null"
10407
11370
  case *types.Struct:
@@ -10420,6 +11383,12 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
10420
11383
  if !ctx.canReferenceNamedType(named) {
10421
11384
  return "any"
10422
11385
  }
11386
+ if _, ok := named.Underlying().(*types.Interface); ok {
11387
+ return "$.VarRef<" + o.tsTypeFor(ctx, typed.Elem()) + "> | null"
11388
+ }
11389
+ if _, ok := types.Unalias(named.Underlying()).(*types.Signature); ok {
11390
+ return "$.VarRef<" + o.tsTypeFor(ctx, typed.Elem()) + "> | null"
11391
+ }
10423
11392
  return "$.VarRef<" + o.namedTypeExpr(ctx, named) + "> | null"
10424
11393
  }
10425
11394
  if named := namedStructType(typed.Elem()); named != nil {
@@ -10462,6 +11431,9 @@ func (o *LoweringOwner) tsNonNilTypeFor(ctx lowerFileContext, typ types.Type) st
10462
11431
  return "Exclude<$.GoError, null>"
10463
11432
  }
10464
11433
  if named, ok := types.Unalias(typ).(*types.Named); ok {
11434
+ if crossPackageUnexportedNamedType(ctx, named) {
11435
+ return "any"
11436
+ }
10465
11437
  if _, ok := named.Underlying().(*types.Interface); ok {
10466
11438
  if !ctx.canReferenceNamedType(named) {
10467
11439
  return "any"
@@ -10788,7 +11760,7 @@ func isPointerToStructType(typ types.Type) bool {
10788
11760
  if !ok {
10789
11761
  return false
10790
11762
  }
10791
- return namedStructType(pointer.Elem()) != nil
11763
+ return structUnderlyingType(pointer.Elem()) != nil
10792
11764
  }
10793
11765
 
10794
11766
  func derefPointerType(typ types.Type) types.Type {
@@ -10865,6 +11837,9 @@ func isChannelType(typ types.Type) bool {
10865
11837
  }
10866
11838
 
10867
11839
  func isComplexType(typ types.Type) bool {
11840
+ if typ == nil {
11841
+ return false
11842
+ }
10868
11843
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10869
11844
  return ok && basic.Info()&types.IsComplex != 0
10870
11845
  }
@@ -10878,10 +11853,21 @@ func isPointerType(typ types.Type) bool {
10878
11853
  }
10879
11854
 
10880
11855
  func isUnsafePointerType(typ types.Type) bool {
11856
+ if typ == nil {
11857
+ return false
11858
+ }
10881
11859
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10882
11860
  return ok && basic.Kind() == types.UnsafePointer
10883
11861
  }
10884
11862
 
11863
+ func isUintptrType(typ types.Type) bool {
11864
+ if typ == nil {
11865
+ return false
11866
+ }
11867
+ basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
11868
+ return ok && basic.Kind() == types.Uintptr
11869
+ }
11870
+
10885
11871
  func channelDirectionString(dir types.ChanDir) string {
10886
11872
  switch dir {
10887
11873
  case types.SendOnly:
@@ -10909,21 +11895,33 @@ func unwrapParenExpr(expr ast.Expr) ast.Expr {
10909
11895
  }
10910
11896
 
10911
11897
  func isStringType(typ types.Type) bool {
11898
+ if typ == nil {
11899
+ return false
11900
+ }
10912
11901
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10913
11902
  return ok && basic.Info()&types.IsString != 0
10914
11903
  }
10915
11904
 
10916
11905
  func isNumericType(typ types.Type) bool {
11906
+ if typ == nil {
11907
+ return false
11908
+ }
10917
11909
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10918
11910
  return ok && basic.Info()&types.IsNumeric != 0
10919
11911
  }
10920
11912
 
10921
11913
  func isIntegerType(typ types.Type) bool {
11914
+ if typ == nil {
11915
+ return false
11916
+ }
10922
11917
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10923
11918
  return ok && basic.Info()&types.IsInteger != 0
10924
11919
  }
10925
11920
 
10926
11921
  func isFloatType(typ types.Type) bool {
11922
+ if typ == nil {
11923
+ return false
11924
+ }
10927
11925
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10928
11926
  return ok && basic.Info()&types.IsFloat != 0
10929
11927
  }
@@ -11097,7 +12095,102 @@ func (o *LoweringOwner) functionAsync(ctx lowerFileContext, fn *types.Func) bool
11097
12095
  if fn == nil || ctx.model == nil {
11098
12096
  return false
11099
12097
  }
11100
- return ctx.model.functionAsync(fn)
12098
+ if ctx.model.functionAsync(fn) {
12099
+ return true
12100
+ }
12101
+ return o.functionReferencesAsyncLazyPackageVar(ctx, fn, make(map[*types.Func]bool))
12102
+ }
12103
+
12104
+ func (o *LoweringOwner) functionReferencesAsyncLazyPackageVar(
12105
+ ctx lowerFileContext,
12106
+ fn *types.Func,
12107
+ seen map[*types.Func]bool,
12108
+ ) bool {
12109
+ fn = functionOriginOrSelf(fn)
12110
+ if fn == nil || ctx.model == nil {
12111
+ return false
12112
+ }
12113
+ if cached, ok := ctx.asyncLazyFunctionCache[fn]; ok {
12114
+ return cached
12115
+ }
12116
+ if ctx.asyncLazyFunctionVisiting != nil {
12117
+ if ctx.asyncLazyFunctionVisiting[fn] {
12118
+ return false
12119
+ }
12120
+ ctx.asyncLazyFunctionVisiting[fn] = true
12121
+ defer delete(ctx.asyncLazyFunctionVisiting, fn)
12122
+ } else {
12123
+ if seen[fn] {
12124
+ return false
12125
+ }
12126
+ seen[fn] = true
12127
+ }
12128
+ references := false
12129
+ defer func() {
12130
+ if ctx.asyncLazyFunctionCache != nil {
12131
+ ctx.asyncLazyFunctionCache[fn] = references
12132
+ }
12133
+ }()
12134
+ if fn.Pkg() == nil {
12135
+ return false
12136
+ }
12137
+ semPkg := ctx.model.packages[fn.Pkg().Path()]
12138
+ if semPkg == nil || semPkg.source == nil {
12139
+ return false
12140
+ }
12141
+ decl := functionDeclForObject(semPkg, fn)
12142
+ if decl == nil || decl.Body == nil {
12143
+ return false
12144
+ }
12145
+ analysisCtx := lowerFileContext{
12146
+ model: ctx.model,
12147
+ semPkg: semPkg,
12148
+ lazyPackageVarsByPkg: ctx.lazyPackageVarsByPkg,
12149
+ asyncLazyFunctionCache: ctx.asyncLazyFunctionCache,
12150
+ asyncLazyFunctionVisiting: ctx.asyncLazyFunctionVisiting,
12151
+ topLevel: true,
12152
+ }
12153
+ ast.Inspect(decl.Body, func(node ast.Node) bool {
12154
+ if references {
12155
+ return false
12156
+ }
12157
+ if _, ok := node.(*ast.FuncLit); ok {
12158
+ return false
12159
+ }
12160
+ if ident, ok := node.(*ast.Ident); ok {
12161
+ if o.objectIsAsyncLazyPackageVar(analysisCtx, semPkg.source.TypesInfo.Uses[ident]) {
12162
+ references = true
12163
+ return false
12164
+ }
12165
+ }
12166
+ if selector, ok := node.(*ast.SelectorExpr); ok {
12167
+ if o.objectIsAsyncLazyPackageVar(analysisCtx, semPkg.source.TypesInfo.Uses[selector.Sel]) {
12168
+ references = true
12169
+ return false
12170
+ }
12171
+ }
12172
+ call, ok := node.(*ast.CallExpr)
12173
+ if !ok {
12174
+ return true
12175
+ }
12176
+ if o.functionReferencesAsyncLazyPackageVar(ctx, calledFunction(semPkg.source, call.Fun), seen) {
12177
+ references = true
12178
+ return false
12179
+ }
12180
+ return true
12181
+ })
12182
+ return references
12183
+ }
12184
+
12185
+ func (o *LoweringOwner) objectIsAsyncLazyPackageVar(ctx lowerFileContext, obj types.Object) bool {
12186
+ varObj, _ := obj.(*types.Var)
12187
+ if varObj == nil || varObj.Pkg() == nil {
12188
+ return false
12189
+ }
12190
+ if !o.packageVarIsLazy(ctx, varObj) && !o.packageVarNameIsLazy(ctx, varObj.Pkg().Path(), varObj.Name()) {
12191
+ return false
12192
+ }
12193
+ return o.packageVarHasAsyncLazyInit(ctx, varObj)
11101
12194
  }
11102
12195
 
11103
12196
  func (o *LoweringOwner) callNeedsAwait(ctx lowerFileContext, fun ast.Expr) bool {