goscript 0.2.4 → 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 (117) 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 +1238 -194
  19. package/compiler/lowering_bench_test.go +4 -0
  20. package/compiler/override-facts.go +1 -1
  21. package/compiler/package-graph.go +92 -0
  22. package/compiler/package-graph_test.go +113 -0
  23. package/compiler/runtime-contract.go +1 -1
  24. package/compiler/semantic-model.go +32 -0
  25. package/compiler/skeleton_test.go +241 -15
  26. package/compiler/wasm/compile.go +1 -1
  27. package/compiler/wasm/compile_test.go +1 -1
  28. package/dist/compiler/index.d.ts +4 -0
  29. package/dist/compiler/index.js +26 -15
  30. package/dist/compiler/index.js.map +1 -1
  31. package/dist/gs/database/sql/driver/index.d.ts +165 -0
  32. package/dist/gs/database/sql/driver/index.js +432 -0
  33. package/dist/gs/database/sql/driver/index.js.map +1 -0
  34. package/dist/gs/encoding/binary/index.d.ts +71 -0
  35. package/dist/gs/encoding/binary/index.js +778 -0
  36. package/dist/gs/encoding/binary/index.js.map +1 -0
  37. package/dist/gs/fmt/fmt.js +156 -57
  38. package/dist/gs/fmt/fmt.js.map +1 -1
  39. package/dist/gs/github.com/klauspost/cpuid/v2/index.d.ts +11 -0
  40. package/dist/gs/github.com/klauspost/cpuid/v2/index.js +28 -0
  41. package/dist/gs/github.com/klauspost/cpuid/v2/index.js.map +1 -0
  42. package/dist/gs/github.com/pkg/errors/errors.d.ts +0 -2
  43. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  44. package/dist/gs/github.com/pkg/errors/index.d.ts +2 -1
  45. package/dist/gs/github.com/pkg/errors/index.js +1 -1
  46. package/dist/gs/github.com/pkg/errors/index.js.map +1 -1
  47. package/dist/gs/github.com/pkg/errors/stack.d.ts +8 -19
  48. package/dist/gs/github.com/pkg/errors/stack.js +26 -61
  49. package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
  50. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.d.ts +19 -0
  51. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js +25 -0
  52. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js.map +1 -0
  53. package/dist/gs/golang.org/x/crypto/cryptobyte/index.d.ts +104 -0
  54. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js +1107 -0
  55. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js.map +1 -0
  56. package/dist/gs/golang.org/x/crypto/internal/alias/index.d.ts +3 -0
  57. package/dist/gs/golang.org/x/crypto/internal/alias/index.js +39 -0
  58. package/dist/gs/golang.org/x/crypto/internal/alias/index.js.map +1 -0
  59. package/dist/gs/runtime/runtime.d.ts +6 -1
  60. package/dist/gs/runtime/runtime.js +15 -8
  61. package/dist/gs/runtime/runtime.js.map +1 -1
  62. package/dist/gs/runtime/trace/index.d.ts +8 -5
  63. package/dist/gs/runtime/trace/index.js +324 -23
  64. package/dist/gs/runtime/trace/index.js.map +1 -1
  65. package/dist/gs/slices/slices.d.ts +2 -1
  66. package/dist/gs/slices/slices.js +9 -3
  67. package/dist/gs/slices/slices.js.map +1 -1
  68. package/dist/gs/sort/search.gs.d.ts +3 -1
  69. package/dist/gs/sort/search.gs.js +18 -53
  70. package/dist/gs/sort/search.gs.js.map +1 -1
  71. package/dist/gs/sync/sync.d.ts +1 -1
  72. package/dist/gs/sync/sync.js +3 -0
  73. package/dist/gs/sync/sync.js.map +1 -1
  74. package/dist/gs/time/time.d.ts +22 -29
  75. package/dist/gs/time/time.js +111 -32
  76. package/dist/gs/time/time.js.map +1 -1
  77. package/dist/gs/unsafe/unsafe.d.ts +3 -2
  78. package/dist/gs/unsafe/unsafe.js.map +1 -1
  79. package/go.mod +7 -5
  80. package/go.sum +12 -26
  81. package/gs/database/sql/driver/index.test.ts +88 -0
  82. package/gs/database/sql/driver/index.ts +675 -0
  83. package/gs/database/sql/driver/meta.json +3 -0
  84. package/gs/database/sql/driver/parity.json +144 -0
  85. package/gs/encoding/binary/index.test.ts +239 -0
  86. package/gs/encoding/binary/index.ts +999 -0
  87. package/gs/encoding/binary/meta.json +9 -0
  88. package/gs/encoding/binary/parity.json +72 -0
  89. package/gs/fmt/fmt.test.ts +28 -0
  90. package/gs/fmt/fmt.ts +198 -61
  91. package/gs/fmt/meta.json +2 -1
  92. package/gs/github.com/klauspost/cpuid/v2/index.ts +38 -0
  93. package/gs/github.com/klauspost/cpuid/v2/meta.json +3 -0
  94. package/gs/github.com/pkg/errors/errors.ts +1 -2
  95. package/gs/github.com/pkg/errors/index.ts +2 -1
  96. package/gs/github.com/pkg/errors/stack.ts +34 -62
  97. package/gs/golang.org/x/crypto/cryptobyte/asn1/index.test.ts +19 -0
  98. package/gs/golang.org/x/crypto/cryptobyte/asn1/index.ts +29 -0
  99. package/gs/golang.org/x/crypto/cryptobyte/index.test.ts +255 -0
  100. package/gs/golang.org/x/crypto/cryptobyte/index.ts +1441 -0
  101. package/gs/golang.org/x/crypto/cryptobyte/meta.json +3 -0
  102. package/gs/golang.org/x/crypto/internal/alias/index.test.ts +40 -0
  103. package/gs/golang.org/x/crypto/internal/alias/index.ts +40 -0
  104. package/gs/runtime/runtime.test.ts +16 -0
  105. package/gs/runtime/runtime.ts +17 -9
  106. package/gs/runtime/trace/index.test.ts +113 -14
  107. package/gs/runtime/trace/index.ts +384 -34
  108. package/gs/runtime/trace/meta.json +1 -0
  109. package/gs/slices/slices.test.ts +24 -1
  110. package/gs/slices/slices.ts +14 -4
  111. package/gs/sort/meta.json +1 -0
  112. package/gs/sort/search.gs.ts +20 -5
  113. package/gs/sync/sync.ts +4 -1
  114. package/gs/time/time.test.ts +79 -2
  115. package/gs/time/time.ts +133 -33
  116. package/gs/unsafe/unsafe.ts +4 -2
  117. 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)
@@ -1853,42 +1937,395 @@ func initializerReferencesLaterPackageVar(
1853
1937
  return references
1854
1938
  }
1855
1939
 
1856
- func initializerCallsFunctionReferencingLaterPackageVar(
1940
+ func initializerCallsFunctionReferencingLaterPackageVar(
1941
+ semPkg *semanticPackage,
1942
+ varOrder map[types.Object]int,
1943
+ current types.Object,
1944
+ expr ast.Expr,
1945
+ ) bool {
1946
+ currentIdx, ok := varOrder[current]
1947
+ if !ok {
1948
+ return false
1949
+ }
1950
+ references := false
1951
+ ast.Inspect(expr, func(node ast.Node) bool {
1952
+ if references {
1953
+ return false
1954
+ }
1955
+ call, ok := node.(*ast.CallExpr)
1956
+ if !ok {
1957
+ return true
1958
+ }
1959
+ fn := calledFunction(semPkg.source, call.Fun)
1960
+ if fn == nil || fn.Pkg() == nil || fn.Pkg().Path() != semPkg.pkgPath {
1961
+ return true
1962
+ }
1963
+ if functionReferencesLaterPackageVar(semPkg, varOrder, currentIdx, fn, nil) {
1964
+ references = true
1965
+ return false
1966
+ }
1967
+ return true
1968
+ })
1969
+ return references
1970
+ }
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
+
2049
+ func functionReferencesLaterPackageVar(
2050
+ semPkg *semanticPackage,
2051
+ varOrder map[types.Object]int,
2052
+ currentIdx int,
2053
+ fn *types.Func,
2054
+ seen map[*types.Func]bool,
2055
+ ) bool {
2056
+ if fn == nil {
2057
+ return false
2058
+ }
2059
+ if seen == nil {
2060
+ seen = make(map[*types.Func]bool)
2061
+ }
2062
+ if seen[fn] {
2063
+ return false
2064
+ }
2065
+ seen[fn] = true
2066
+ fnDecl := functionDeclForObject(semPkg, fn)
2067
+ if fnDecl == nil || fnDecl.Body == nil {
2068
+ return false
2069
+ }
2070
+ references := false
2071
+ ast.Inspect(fnDecl.Body, func(node ast.Node) bool {
2072
+ if references {
2073
+ return false
2074
+ }
2075
+ if _, ok := node.(*ast.FuncLit); ok {
2076
+ return false
2077
+ }
2078
+ if ident, ok := node.(*ast.Ident); ok {
2079
+ if obj, ok := semPkg.source.TypesInfo.Uses[ident].(*types.Var); ok &&
2080
+ obj.Pkg() != nil && obj.Pkg().Path() == semPkg.pkgPath {
2081
+ if idx, ok := varOrder[obj]; ok && idx > currentIdx {
2082
+ references = true
2083
+ return false
2084
+ }
2085
+ }
2086
+ }
2087
+ if call, ok := node.(*ast.CallExpr); ok {
2088
+ called := calledFunction(semPkg.source, call.Fun)
2089
+ if called != nil && called.Pkg() != nil && called.Pkg().Path() == semPkg.pkgPath &&
2090
+ functionReferencesLaterPackageVar(semPkg, varOrder, currentIdx, called, seen) {
2091
+ references = true
2092
+ return false
2093
+ }
2094
+ }
2095
+ return true
2096
+ })
2097
+ return references
2098
+ }
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(
1857
2285
  semPkg *semanticPackage,
1858
- varOrder map[types.Object]int,
1859
- current types.Object,
1860
- expr ast.Expr,
2286
+ declFiles map[types.Object]string,
2287
+ ident *ast.Ident,
2288
+ sourcePath string,
1861
2289
  ) bool {
1862
- currentIdx, ok := varOrder[current]
1863
- if !ok {
2290
+ if tv, ok := semPkg.source.TypesInfo.Types[ident]; ok && !tv.IsValue() {
1864
2291
  return false
1865
2292
  }
1866
- references := false
1867
- ast.Inspect(expr, func(node ast.Node) bool {
1868
- if references {
1869
- return false
1870
- }
1871
- call, ok := node.(*ast.CallExpr)
1872
- if !ok {
1873
- return true
1874
- }
1875
- fn := calledFunction(semPkg.source, call.Fun)
1876
- if fn == nil || fn.Pkg() == nil || fn.Pkg().Path() != semPkg.pkgPath {
1877
- return true
1878
- }
1879
- if functionReferencesLaterPackageVar(semPkg, varOrder, currentIdx, fn, nil) {
1880
- references = true
1881
- return false
1882
- }
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 {
1883
2306
  return true
1884
- })
1885
- return references
2307
+ }
2308
+ if selection := semPkg.source.TypesInfo.Selections[selector]; selection != nil {
2309
+ return declFiles[selection.Obj()] == sourcePath
2310
+ }
2311
+ return false
1886
2312
  }
1887
2313
 
1888
- func functionReferencesLaterPackageVar(
2314
+ func typeReferencesSourceFile(
1889
2315
  semPkg *semanticPackage,
1890
- varOrder map[types.Object]int,
1891
- currentIdx int,
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,
1892
2329
  fn *types.Func,
1893
2330
  seen map[*types.Func]bool,
1894
2331
  ) bool {
@@ -1914,10 +2351,16 @@ func functionReferencesLaterPackageVar(
1914
2351
  if _, ok := node.(*ast.FuncLit); ok {
1915
2352
  return false
1916
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
+ }
1917
2360
  if ident, ok := node.(*ast.Ident); ok {
1918
- if obj, ok := semPkg.source.TypesInfo.Uses[ident].(*types.Var); ok &&
1919
- obj.Pkg() != nil && obj.Pkg().Path() == semPkg.pkgPath {
1920
- if idx, ok := varOrder[obj]; ok && idx > currentIdx {
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 {
1921
2364
  references = true
1922
2365
  return false
1923
2366
  }
@@ -1926,7 +2369,7 @@ func functionReferencesLaterPackageVar(
1926
2369
  if call, ok := node.(*ast.CallExpr); ok {
1927
2370
  called := calledFunction(semPkg.source, call.Fun)
1928
2371
  if called != nil && called.Pkg() != nil && called.Pkg().Path() == semPkg.pkgPath &&
1929
- functionReferencesLaterPackageVar(semPkg, varOrder, currentIdx, called, seen) {
2372
+ functionReferencesOtherFileObject(semPkg, declFiles, sourcePath, called, seen) {
1930
2373
  references = true
1931
2374
  return false
1932
2375
  }
@@ -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:
@@ -6868,6 +7439,21 @@ func (o *LoweringOwner) lowerFuncLitWithAsyncCalls(
6868
7439
  lit *ast.FuncLit,
6869
7440
  allowAsyncCalls bool,
6870
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) {
6871
7457
  signature, _ := ctx.semPkg.source.TypesInfo.TypeOf(lit).(*types.Signature)
6872
7458
  deferState := &loweredDeferState{}
6873
7459
  bodyCtx := ctx.withSignature(signature).withAsyncFunction(false).withDeferState(deferState).withoutRangeBranch()
@@ -6897,8 +7483,7 @@ func (o *LoweringOwner) lowerFuncLitWithAsyncCalls(
6897
7483
  function := prefix + "(" + renderLoweredParams(params) + "): " +
6898
7484
  asyncResultType(o.tsSignatureResultFor(ctx, signature), async) + " => {\n" +
6899
7485
  rendered.String() + "}"
6900
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperFunctionValue) +
6901
- "(" + function + ", " + o.runtimeFunctionTypeInfo(signature, "") + ")", async, diagnostics
7486
+ return function, async, signature, diagnostics
6902
7487
  }
6903
7488
 
6904
7489
  func renderLoweredParams(params []loweredParam) string {
@@ -6997,6 +7582,9 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
6997
7582
  return constValue
6998
7583
  }
6999
7584
  }
7585
+ if imported, ok := o.lowerImportedIdent(ctx, obj, value, raw); ok {
7586
+ return imported
7587
+ }
7000
7588
  if alias := ctx.localAliases[obj]; alias != "" {
7001
7589
  if ctx.lazyPackageVars[obj] {
7002
7590
  lazyValue := alias + "." + packageVarGetterName(value) + "()"
@@ -7029,6 +7617,29 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
7029
7617
  return value
7030
7618
  }
7031
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
+
7032
7643
  func (o *LoweringOwner) lowerPackageVarReadValue(ctx lowerFileContext, obj types.Object, value string) string {
7033
7644
  if obj == nil || ctx.model == nil || !ctx.model.needsVarRef[obj] {
7034
7645
  return value
@@ -7103,6 +7714,17 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
7103
7714
  }
7104
7715
 
7105
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
+ }
7106
7728
 
7107
7729
  switch fun := expr.Fun.(type) {
7108
7730
  case *ast.Ident:
@@ -7260,16 +7882,6 @@ func (o *LoweringOwner) lowerCallExpr(ctx lowerFileContext, expr *ast.CallExpr)
7260
7882
  ctx.deferState.async = true
7261
7883
  }
7262
7884
  return o.awaitCallIfNeeded(ctx, fun, call), append(diagnostics, calleeDiagnostics...)
7263
- case *ast.FuncLit:
7264
- callee, async, calleeDiagnostics := o.lowerFuncLit(ctx, fun)
7265
- call := "(" + callee + ")(" + strings.Join(args, ", ") + ")"
7266
- if async {
7267
- call = "await " + call
7268
- if ctx.deferState != nil {
7269
- ctx.deferState.async = true
7270
- }
7271
- }
7272
- return call, append(diagnostics, calleeDiagnostics...)
7273
7885
  default:
7274
7886
  if callTargetSignature(ctx, expr.Fun) != nil {
7275
7887
  callee, calleeDiagnostics := o.lowerExpr(ctx, expr.Fun)
@@ -7680,6 +8292,11 @@ func (o *LoweringOwner) lowerConversionExpr(
7680
8292
  if value, addressDiagnostics, ok := o.lowerUnsafePointerIntegerExpr(ctx, expr.Args[0]); ok {
7681
8293
  return value, append(diagnostics, addressDiagnostics...)
7682
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
+ }
7683
8300
  }
7684
8301
  if helper, addressDiagnostics, ok := o.lowerReflectHeaderPointerConversion(ctx, targetType, expr.Args[0]); ok {
7685
8302
  return helper, append(diagnostics, addressDiagnostics...)
@@ -7688,6 +8305,9 @@ func (o *LoweringOwner) lowerConversionExpr(
7688
8305
  return helper, append(diagnostics, addressDiagnostics...)
7689
8306
  }
7690
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
+ }
7691
8311
  return "(" + value + " as any)", diagnostics
7692
8312
  }
7693
8313
  if isNilExpr(expr.Args[0]) && isPointerType(targetType) {
@@ -7838,6 +8458,12 @@ func (o *LoweringOwner) lowerWideIntegerBinaryExpr(ctx lowerFileContext, expr *a
7838
8458
  case token.AND:
7839
8459
  return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64And, RuntimeHelperInt64And)) + "(" + left + ", " + right + ")", true
7840
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
+ }
7841
8467
  return o.runtimeOwner.QualifiedHelper(wideIntegerHelper(signed, RuntimeHelperUint64Xor, RuntimeHelperInt64Xor)) + "(" + left + ", " + right + ")", true
7842
8468
  case token.OR:
7843
8469
  shift, ok := wideLeftShiftExpr(ctx, expr.X)
@@ -7909,6 +8535,11 @@ func lowIntegerBits(ctx lowerFileContext, expr ast.Expr) (int, bool) {
7909
8535
  return integerBits(ctx.semPkg.source.TypesInfo.TypeOf(expr))
7910
8536
  }
7911
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
+
7912
8543
  func shiftMultiplier(amount int) string {
7913
8544
  return "(2 ** " + strconv.Itoa(amount) + ")"
7914
8545
  }
@@ -8359,6 +8990,9 @@ func (o *LoweringOwner) lowerFieldSelectionExpr(
8359
8990
  selection *types.Selection,
8360
8991
  address bool,
8361
8992
  ) (string, []Diagnostic) {
8993
+ if value, diagnostics, ok := o.lowerUnsafeStructFieldSelectionExpr(ctx, expr, selection, address); ok {
8994
+ return value, diagnostics
8995
+ }
8362
8996
  receiver, diagnostics := o.lowerFieldReceiverExpr(ctx, expr.X)
8363
8997
  receiver = parenthesizeAwaitedExpr(receiver)
8364
8998
  index := selection.Index()
@@ -8369,46 +9003,117 @@ func (o *LoweringOwner) lowerFieldSelectionExpr(
8369
9003
  }
8370
9004
  return receiver + "." + fieldName, diagnostics
8371
9005
  }
8372
-
8373
- typ := derefPointerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
8374
- for idx, fieldIndex := range index {
8375
- structType := structUnderlyingType(typ)
8376
- if structType == nil || fieldIndex < 0 || fieldIndex >= structType.NumFields() {
8377
- fieldName := tsStructFieldName(expr.Sel.Name, 0)
8378
- if address {
8379
- return receiver + "._fields." + fieldName, diagnostics
8380
- }
8381
- return receiver + "." + fieldName, diagnostics
8382
- }
8383
- field := structType.Field(fieldIndex)
8384
- name := tsStructFieldName(field.Name(), fieldIndex)
8385
- if idx == len(index)-1 {
8386
- if address {
8387
- return o.lowerFieldAddressExpr(ctx, receiver, typ, name), diagnostics
8388
- }
8389
- return receiver + "." + name, diagnostics
8390
- }
8391
-
8392
- receiver += "." + name
8393
- typ = field.Type()
8394
- if pointer, ok := types.Unalias(typ).Underlying().(*types.Pointer); ok {
8395
- receiver = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
8396
- "<" + o.tsTypeFor(ctx, pointer.Elem()) + ">(" + receiver + ")"
8397
- typ = pointer.Elem()
8398
- }
9006
+
9007
+ typ := derefPointerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
9008
+ for idx, fieldIndex := range index {
9009
+ structType := structUnderlyingType(typ)
9010
+ if structType == nil || fieldIndex < 0 || fieldIndex >= structType.NumFields() {
9011
+ fieldName := tsStructFieldName(expr.Sel.Name, 0)
9012
+ if address {
9013
+ return receiver + "._fields." + fieldName, diagnostics
9014
+ }
9015
+ return receiver + "." + fieldName, diagnostics
9016
+ }
9017
+ field := structType.Field(fieldIndex)
9018
+ name := tsStructFieldName(field.Name(), fieldIndex)
9019
+ if idx == len(index)-1 {
9020
+ if address {
9021
+ return o.lowerFieldAddressExpr(ctx, receiver, typ, name), diagnostics
9022
+ }
9023
+ return receiver + "." + name, diagnostics
9024
+ }
9025
+
9026
+ receiver += "." + name
9027
+ typ = field.Type()
9028
+ if pointer, ok := types.Unalias(typ).Underlying().(*types.Pointer); ok {
9029
+ receiver = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
9030
+ "<" + o.tsTypeFor(ctx, pointer.Elem()) + ">(" + receiver + ")"
9031
+ typ = pointer.Elem()
9032
+ }
9033
+ }
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])
9097
+ if address {
9098
+ return o.lowerFieldAddressExpr(ctx, receiver, sourcePointer.Elem(), fieldName), diagnostics, true
8399
9099
  }
9100
+ return receiver + "." + fieldName, diagnostics, true
9101
+ }
8400
9102
 
8401
- if address {
8402
- return o.lowerFieldAddressExpr(ctx, receiver, typ, tsStructFieldName(expr.Sel.Name, 0)), diagnostics
9103
+ func unsafeStructFieldLayoutCompatible(target *types.Var, source *types.Var) bool {
9104
+ if target == nil || source == nil || target.Name() != source.Name() {
9105
+ return false
8403
9106
  }
8404
- return receiver + "." + tsStructFieldName(expr.Sel.Name, 0), diagnostics
9107
+ return unsafeFieldTypeLayoutCompatible(target.Type(), source.Type())
8405
9108
  }
8406
9109
 
8407
- func (o *LoweringOwner) lowerFieldAddressExpr(ctx lowerFileContext, receiver string, typ types.Type, fieldName string) string {
8408
- if namedStructType(derefPointerType(typ)) != nil {
8409
- return receiver + "._fields." + fieldName
9110
+ func unsafeFieldTypeLayoutCompatible(left types.Type, right types.Type) bool {
9111
+ if types.Identical(left, right) {
9112
+ return true
8410
9113
  }
8411
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperFieldRef) + "(" + receiver + ", " + strconv.Quote(fieldName) + ")"
9114
+ leftUnderlying := types.Unalias(left).Underlying()
9115
+ rightUnderlying := types.Unalias(right).Underlying()
9116
+ return types.Identical(leftUnderlying, rightUnderlying)
8412
9117
  }
8413
9118
 
8414
9119
  func (o *LoweringOwner) lowerMethodValueClosure(
@@ -8494,6 +9199,9 @@ func fieldReceiverNeedsVarRefValue(ctx lowerFileContext, expr ast.Expr, obj type
8494
9199
  return true
8495
9200
  }
8496
9201
  if ctx.identAliases[obj] != "" {
9202
+ if obj == nil || ctx.model == nil || !ctx.model.needsVarRef[obj] {
9203
+ return false
9204
+ }
8497
9205
  return !ctx.identAliasRefs[obj]
8498
9206
  }
8499
9207
  if ctx.localAliases[obj] != "" {
@@ -8654,6 +9362,10 @@ func (o *LoweringOwner) lowerAddressExpr(ctx lowerFileContext, expr ast.Expr) (s
8654
9362
  return receiver + "._fields." + typed.Sel.Name, diagnostics
8655
9363
  case *ast.IndexExpr:
8656
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)
8657
9369
  default:
8658
9370
  return "undefined", []Diagnostic{loweringUnsupportedAt(ctx, typed, "expression", ctx.semPkg.pkgPath, "unsupported address expression")}
8659
9371
  }
@@ -8745,6 +9457,35 @@ func (o *LoweringOwner) lowerUnsafePointerIntegerExpr(
8745
9457
  return o.lowerIndexByteAddressIntegerExpr(ctx, call.Args[0])
8746
9458
  }
8747
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
+
8748
9489
  func (o *LoweringOwner) lowerIndexAddressIntegerExpr(
8749
9490
  ctx lowerFileContext,
8750
9491
  expr ast.Expr,
@@ -8915,6 +9656,9 @@ func (o *LoweringOwner) lowerUnsafeArrayPointerConversion(
8915
9656
  targetType types.Type,
8916
9657
  expr ast.Expr,
8917
9658
  ) (string, []Diagnostic, bool) {
9659
+ if targetType == nil {
9660
+ return "", nil, false
9661
+ }
8918
9662
  targetPointer, _ := types.Unalias(targetType).Underlying().(*types.Pointer)
8919
9663
  if targetPointer == nil {
8920
9664
  return "", nil, false
@@ -8923,29 +9667,191 @@ func (o *LoweringOwner) lowerUnsafeArrayPointerConversion(
8923
9667
  if array == nil {
8924
9668
  return "", nil, false
8925
9669
  }
8926
- unsafeCall, ok := unwrapParenExpr(expr).(*ast.CallExpr)
8927
- if !ok || len(unsafeCall.Args) != 1 || !isUnsafePointerType(typeFromExpr(ctx, unsafeCall.Fun)) {
8928
- return "", nil, false
8929
- }
8930
- address, ok := unwrapParenExpr(unsafeCall.Args[0]).(*ast.UnaryExpr)
8931
- if !ok || address.Op != token.AND {
8932
- return "", nil, false
8933
- }
8934
- index, ok := unwrapParenExpr(address.X).(*ast.IndexExpr)
9670
+ ref, sourceType, diagnostics, ok := o.lowerUnsafeArrayPointerSourceRef(ctx, expr)
8935
9671
  if !ok {
8936
9672
  return "", nil, false
8937
9673
  }
8938
- ref, diagnostics := o.lowerAddressExpr(ctx, index)
8939
- sourceElementSize := goScriptElementByteSize(ctx, indexElementType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)))
9674
+ sourceElementSize := goScriptElementByteSize(ctx, sourceType)
8940
9675
  targetElementSize := goScriptElementByteSize(ctx, array.Elem())
9676
+ sourceTypeArg := o.tsTypeFor(ctx, array.Elem())
9677
+ if sourceType != nil {
9678
+ sourceTypeArg = o.tsTypeFor(ctx, sourceType)
9679
+ }
8941
9680
  helper := o.runtimeOwner.QualifiedHelper(RuntimeHelperArrayPointerFromIndexRef) +
8942
- "<" + o.tsTypeFor(ctx, array.Elem()) + ">(" + ref + ", " +
9681
+ "<" + sourceTypeArg + ">(" + ref + ", " +
8943
9682
  strconv.FormatInt(array.Len(), 10) + ", " +
8944
9683
  strconv.FormatInt(sourceElementSize, 10) + ", " +
8945
9684
  strconv.FormatInt(targetElementSize, 10) + ")"
8946
9685
  return "(" + helper + " as unknown as " + o.tsTypeFor(ctx, targetType) + ")", diagnostics, true
8947
9686
  }
8948
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
+
8949
9855
  func (o *LoweringOwner) lowerAddressedValueRef(ctx lowerFileContext, expr ast.Expr) (string, []Diagnostic) {
8950
9856
  if ident, ok := unwrapParenExpr(expr).(*ast.Ident); ok {
8951
9857
  if obj := objectForIdent(ctx, ident); obj != nil && ctx.model.needsVarRef[obj] {
@@ -9523,7 +10429,11 @@ func (o *LoweringOwner) lowerMapCompositeLit(
9523
10429
  value = o.lowerValueForTarget(ctx, keyed.Value, mapType.Elem(), value)
9524
10430
  entries = append(entries, "["+key+", "+value+"]")
9525
10431
  }
9526
- 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 + ">"
9527
10437
  }
9528
10438
 
9529
10439
  func (o *LoweringOwner) lowerTypeAssertExpr(ctx lowerFileContext, expr *ast.TypeAssertExpr) (string, []Diagnostic) {
@@ -9560,7 +10470,11 @@ func (o *LoweringOwner) lowerMapGetTuple(ctx lowerFileContext, expr *ast.IndexEx
9560
10470
  mapType, _ := types.Unalias(ctx.semPkg.source.TypesInfo.TypeOf(expr.X)).Underlying().(*types.Map)
9561
10471
  defaultValue := "undefined"
9562
10472
  if mapType != nil {
10473
+ index = o.lowerValueForTarget(ctx, expr.Index, mapType.Key(), index)
9563
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 + ")"
9564
10478
  }
9565
10479
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperMapGet) + "(" + target + ", " + index + ", " + defaultValue + ")"
9566
10480
  }
@@ -10450,7 +11364,7 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
10450
11364
  case *types.Slice:
10451
11365
  return "$.Slice<" + o.tsSliceElemTypeFor(ctx, typed.Elem()) + ">"
10452
11366
  case *types.Map:
10453
- 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"
10454
11368
  case *types.Chan:
10455
11369
  return "$.Channel<" + o.tsTypeFor(ctx, typed.Elem()) + "> | null"
10456
11370
  case *types.Struct:
@@ -10469,6 +11383,12 @@ func (o *LoweringOwner) tsTypeFor(ctx lowerFileContext, typ types.Type) string {
10469
11383
  if !ctx.canReferenceNamedType(named) {
10470
11384
  return "any"
10471
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
+ }
10472
11392
  return "$.VarRef<" + o.namedTypeExpr(ctx, named) + "> | null"
10473
11393
  }
10474
11394
  if named := namedStructType(typed.Elem()); named != nil {
@@ -10511,6 +11431,9 @@ func (o *LoweringOwner) tsNonNilTypeFor(ctx lowerFileContext, typ types.Type) st
10511
11431
  return "Exclude<$.GoError, null>"
10512
11432
  }
10513
11433
  if named, ok := types.Unalias(typ).(*types.Named); ok {
11434
+ if crossPackageUnexportedNamedType(ctx, named) {
11435
+ return "any"
11436
+ }
10514
11437
  if _, ok := named.Underlying().(*types.Interface); ok {
10515
11438
  if !ctx.canReferenceNamedType(named) {
10516
11439
  return "any"
@@ -10837,7 +11760,7 @@ func isPointerToStructType(typ types.Type) bool {
10837
11760
  if !ok {
10838
11761
  return false
10839
11762
  }
10840
- return namedStructType(pointer.Elem()) != nil
11763
+ return structUnderlyingType(pointer.Elem()) != nil
10841
11764
  }
10842
11765
 
10843
11766
  func derefPointerType(typ types.Type) types.Type {
@@ -10914,6 +11837,9 @@ func isChannelType(typ types.Type) bool {
10914
11837
  }
10915
11838
 
10916
11839
  func isComplexType(typ types.Type) bool {
11840
+ if typ == nil {
11841
+ return false
11842
+ }
10917
11843
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10918
11844
  return ok && basic.Info()&types.IsComplex != 0
10919
11845
  }
@@ -10927,10 +11853,21 @@ func isPointerType(typ types.Type) bool {
10927
11853
  }
10928
11854
 
10929
11855
  func isUnsafePointerType(typ types.Type) bool {
11856
+ if typ == nil {
11857
+ return false
11858
+ }
10930
11859
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10931
11860
  return ok && basic.Kind() == types.UnsafePointer
10932
11861
  }
10933
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
+
10934
11871
  func channelDirectionString(dir types.ChanDir) string {
10935
11872
  switch dir {
10936
11873
  case types.SendOnly:
@@ -10958,21 +11895,33 @@ func unwrapParenExpr(expr ast.Expr) ast.Expr {
10958
11895
  }
10959
11896
 
10960
11897
  func isStringType(typ types.Type) bool {
11898
+ if typ == nil {
11899
+ return false
11900
+ }
10961
11901
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10962
11902
  return ok && basic.Info()&types.IsString != 0
10963
11903
  }
10964
11904
 
10965
11905
  func isNumericType(typ types.Type) bool {
11906
+ if typ == nil {
11907
+ return false
11908
+ }
10966
11909
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10967
11910
  return ok && basic.Info()&types.IsNumeric != 0
10968
11911
  }
10969
11912
 
10970
11913
  func isIntegerType(typ types.Type) bool {
11914
+ if typ == nil {
11915
+ return false
11916
+ }
10971
11917
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10972
11918
  return ok && basic.Info()&types.IsInteger != 0
10973
11919
  }
10974
11920
 
10975
11921
  func isFloatType(typ types.Type) bool {
11922
+ if typ == nil {
11923
+ return false
11924
+ }
10976
11925
  basic, ok := types.Unalias(typ).Underlying().(*types.Basic)
10977
11926
  return ok && basic.Info()&types.IsFloat != 0
10978
11927
  }
@@ -11146,7 +12095,102 @@ func (o *LoweringOwner) functionAsync(ctx lowerFileContext, fn *types.Func) bool
11146
12095
  if fn == nil || ctx.model == nil {
11147
12096
  return false
11148
12097
  }
11149
- 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)
11150
12194
  }
11151
12195
 
11152
12196
  func (o *LoweringOwner) callNeedsAwait(ctx lowerFileContext, fun ast.Expr) bool {