goscript 0.1.2 → 0.1.4

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 (138) hide show
  1. package/cmd/goscript/cmd_compile.go +28 -8
  2. package/cmd/goscript/cmd_compile_test.go +105 -6
  3. package/compiler/build-flags.go +9 -10
  4. package/compiler/gotest/runner_test.go +127 -0
  5. package/compiler/lowered-program.go +1 -0
  6. package/compiler/lowering.go +1325 -194
  7. package/compiler/lowering_bench_test.go +350 -0
  8. package/compiler/override-registry_test.go +43 -0
  9. package/compiler/package-graph.go +61 -4
  10. package/compiler/package-graph_test.go +30 -0
  11. package/compiler/semantic-model-types.go +8 -0
  12. package/compiler/semantic-model.go +447 -22
  13. package/compiler/semantic-model_test.go +138 -0
  14. package/compiler/skeleton_test.go +1436 -50
  15. package/compiler/typescript-emitter.go +47 -4
  16. package/dist/gs/builtin/builtin.d.ts +2 -2
  17. package/dist/gs/builtin/builtin.js +20 -0
  18. package/dist/gs/builtin/builtin.js.map +1 -1
  19. package/dist/gs/builtin/channel.js +36 -9
  20. package/dist/gs/builtin/channel.js.map +1 -1
  21. package/dist/gs/builtin/slice.js +5 -0
  22. package/dist/gs/builtin/slice.js.map +1 -1
  23. package/dist/gs/builtin/type.d.ts +1 -1
  24. package/dist/gs/builtin/type.js +80 -8
  25. package/dist/gs/builtin/type.js.map +1 -1
  26. package/dist/gs/bytes/bytes.gs.d.ts +7 -5
  27. package/dist/gs/bytes/bytes.gs.js +10 -4
  28. package/dist/gs/bytes/bytes.gs.js.map +1 -1
  29. package/dist/gs/compress/zlib/index.d.ts +3 -3
  30. package/dist/gs/compress/zlib/index.js +88 -26
  31. package/dist/gs/compress/zlib/index.js.map +1 -1
  32. package/dist/gs/crypto/sha1/index.d.ts +5 -0
  33. package/dist/gs/crypto/sha1/index.js +103 -0
  34. package/dist/gs/crypto/sha1/index.js.map +1 -0
  35. package/dist/gs/crypto/sha256/index.js +2 -5
  36. package/dist/gs/crypto/sha256/index.js.map +1 -1
  37. package/dist/gs/crypto/sha512/index.js +2 -5
  38. package/dist/gs/crypto/sha512/index.js.map +1 -1
  39. package/dist/gs/embed/index.d.ts +6 -0
  40. package/dist/gs/embed/index.js +210 -5
  41. package/dist/gs/embed/index.js.map +1 -1
  42. package/dist/gs/fmt/fmt.d.ts +4 -4
  43. package/dist/gs/fmt/fmt.js +93 -19
  44. package/dist/gs/fmt/fmt.js.map +1 -1
  45. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +118 -6
  46. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
  47. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  48. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  49. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  50. package/dist/gs/io/fs/readdir.js +5 -3
  51. package/dist/gs/io/fs/readdir.js.map +1 -1
  52. package/dist/gs/io/io.d.ts +18 -11
  53. package/dist/gs/io/io.js +107 -44
  54. package/dist/gs/io/io.js.map +1 -1
  55. package/dist/gs/math/bits/index.d.ts +26 -5
  56. package/dist/gs/math/bits/index.js +13 -24
  57. package/dist/gs/math/bits/index.js.map +1 -1
  58. package/dist/gs/net/http/httptest/index.js +7 -5
  59. package/dist/gs/net/http/httptest/index.js.map +1 -1
  60. package/dist/gs/net/http/index.d.ts +11 -1
  61. package/dist/gs/net/http/index.js +157 -11
  62. package/dist/gs/net/http/index.js.map +1 -1
  63. package/dist/gs/os/types_js.gs.d.ts +6 -2
  64. package/dist/gs/os/types_js.gs.js +169 -8
  65. package/dist/gs/os/types_js.gs.js.map +1 -1
  66. package/dist/gs/os/zero_copy_posix.gs.js +1 -1
  67. package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
  68. package/dist/gs/reflect/type.d.ts +1 -0
  69. package/dist/gs/reflect/type.js +80 -51
  70. package/dist/gs/reflect/type.js.map +1 -1
  71. package/dist/gs/strings/reader.d.ts +1 -1
  72. package/dist/gs/strings/reader.js +2 -2
  73. package/dist/gs/strings/reader.js.map +1 -1
  74. package/dist/gs/sync/sync.d.ts +2 -1
  75. package/dist/gs/sync/sync.js +37 -16
  76. package/dist/gs/sync/sync.js.map +1 -1
  77. package/dist/gs/syscall/js/index.js +9 -0
  78. package/dist/gs/syscall/js/index.js.map +1 -1
  79. package/dist/gs/testing/testing.js +8 -6
  80. package/dist/gs/testing/testing.js.map +1 -1
  81. package/gs/builtin/builtin.ts +25 -2
  82. package/gs/builtin/channel.ts +47 -9
  83. package/gs/builtin/runtime-contract.test.ts +78 -0
  84. package/gs/builtin/slice.ts +7 -0
  85. package/gs/builtin/type.ts +97 -8
  86. package/gs/bytes/bytes.gs.ts +19 -10
  87. package/gs/bytes/bytes.test.ts +17 -0
  88. package/gs/compress/zlib/index.test.ts +97 -0
  89. package/gs/compress/zlib/index.ts +117 -27
  90. package/gs/compress/zlib/meta.json +4 -1
  91. package/gs/context/context.test.ts +5 -1
  92. package/gs/crypto/sha1/index.test.ts +45 -0
  93. package/gs/crypto/sha1/index.ts +127 -0
  94. package/gs/crypto/sha1/meta.json +8 -0
  95. package/gs/crypto/sha256/index.test.ts +14 -2
  96. package/gs/crypto/sha256/index.ts +3 -6
  97. package/gs/crypto/sha512/index.test.ts +17 -2
  98. package/gs/crypto/sha512/index.ts +3 -6
  99. package/gs/embed/index.test.ts +87 -0
  100. package/gs/embed/index.ts +229 -5
  101. package/gs/fmt/fmt.test.ts +61 -3
  102. package/gs/fmt/fmt.ts +115 -22
  103. package/gs/fmt/meta.json +6 -1
  104. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +8 -1
  105. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +139 -11
  106. package/gs/github.com/aperturerobotics/util/conc/index.test.ts +1 -1
  107. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  108. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  109. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  110. package/gs/io/fs/readdir.test.ts +38 -0
  111. package/gs/io/fs/readdir.ts +7 -3
  112. package/gs/io/io.test.ts +135 -0
  113. package/gs/io/io.ts +143 -63
  114. package/gs/io/meta.json +7 -1
  115. package/gs/math/bits/index.ts +52 -28
  116. package/gs/net/http/httptest/index.test.ts +34 -2
  117. package/gs/net/http/httptest/index.ts +23 -8
  118. package/gs/net/http/index.test.ts +46 -0
  119. package/gs/net/http/index.ts +178 -12
  120. package/gs/os/file_unix_js.test.ts +52 -0
  121. package/gs/os/meta.json +4 -0
  122. package/gs/os/readdir.test.ts +56 -0
  123. package/gs/os/types_js.gs.ts +169 -8
  124. package/gs/os/zero_copy_posix.gs.ts +1 -2
  125. package/gs/reflect/deepequal.test.ts +10 -1
  126. package/gs/reflect/type.ts +91 -56
  127. package/gs/reflect/typefor.test.ts +31 -1
  128. package/gs/strings/meta.json +5 -2
  129. package/gs/strings/reader.test.ts +2 -2
  130. package/gs/strings/reader.ts +2 -2
  131. package/gs/sync/meta.json +2 -0
  132. package/gs/sync/sync.test.ts +41 -1
  133. package/gs/sync/sync.ts +41 -16
  134. package/gs/syscall/js/index.test.ts +18 -0
  135. package/gs/syscall/js/index.ts +12 -0
  136. package/gs/testing/testing.test.ts +32 -3
  137. package/gs/testing/testing.ts +13 -10
  138. package/package.json +1 -1
@@ -187,9 +187,6 @@ func (o *LoweringOwner) lowerFile(
187
187
  })
188
188
  }
189
189
  }
190
- for importSourcePath := range relevantImportFiles {
191
- o.addGeneratedTypeImports(model, semPkg, importSourcePath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport)
192
- }
193
190
  implicitImportPaths := make([]string, 0, len(localRefs.implicitImports))
194
191
  for pkgPath := range localRefs.implicitImports {
195
192
  if pkgPath != "" && pkgPath != semPkg.pkgPath {
@@ -198,7 +195,19 @@ func (o *LoweringOwner) lowerFile(
198
195
  }
199
196
  slices.Sort(implicitImportPaths)
200
197
  for _, pkgPath := range implicitImportPaths {
201
- o.addGeneratedImportPath(model, pkgPath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport)
198
+ o.addGeneratedImportPath(
199
+ model,
200
+ pkgPath,
201
+ loweredFile,
202
+ importAliases,
203
+ importPaths,
204
+ reservedImportAliases,
205
+ seenImport,
206
+ !localRefs.implicitRuntime[pkgPath],
207
+ )
208
+ }
209
+ for importSourcePath := range relevantImportFiles {
210
+ o.addGeneratedTypeImports(model, semPkg, importSourcePath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport)
202
211
  }
203
212
  localImports := make([]loweredImport, 0, len(localRefs.aliases))
204
213
  seenLocalImport := make(map[string]bool)
@@ -208,7 +217,13 @@ func (o *LoweringOwner) lowerFile(
208
217
  }
209
218
  seenLocalImport[alias] = true
210
219
  source := localRefs.aliasSources[alias]
211
- localImports = append(localImports, loweredImport{alias: alias, source: source, sideEffect: true})
220
+ typeOnly := !localRefs.runtimeAliases[alias]
221
+ localImports = append(localImports, loweredImport{
222
+ alias: alias,
223
+ source: source,
224
+ sideEffect: !typeOnly,
225
+ typeOnly: typeOnly,
226
+ })
212
227
  }
213
228
  slices.SortFunc(localImports, func(a, b loweredImport) int {
214
229
  return cmp.Compare(a.alias, b.alias)
@@ -308,7 +323,7 @@ func (o *LoweringOwner) addGeneratedTypeImports(
308
323
  }
309
324
  slices.Sort(pkgPaths)
310
325
  for _, pkgPath := range pkgPaths {
311
- o.addGeneratedImportPath(model, pkgPath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport)
326
+ o.addGeneratedImportPath(model, pkgPath, loweredFile, importAliases, importPaths, reservedImportAliases, seenImport, true)
312
327
  }
313
328
  }
314
329
 
@@ -320,6 +335,7 @@ func (o *LoweringOwner) addGeneratedImportPath(
320
335
  importPaths map[string]string,
321
336
  reservedImportAliases map[string]bool,
322
337
  seenImport map[string]bool,
338
+ typeOnly bool,
323
339
  ) {
324
340
  if !o.hasGeneratedImportPackage(model, pkgPath) {
325
341
  return
@@ -340,7 +356,8 @@ func (o *LoweringOwner) addGeneratedImportPath(
340
356
  loweredFile.imports = append(loweredFile.imports, loweredImport{
341
357
  alias: alias,
342
358
  source: source,
343
- sideEffect: true,
359
+ sideEffect: !typeOnly,
360
+ typeOnly: typeOnly,
344
361
  })
345
362
  }
346
363
 
@@ -429,7 +446,9 @@ type localFileReferenceAnalysis struct {
429
446
  reservedNames map[string]bool
430
447
  aliases map[types.Object]string
431
448
  aliasSources map[string]string
449
+ runtimeAliases map[string]bool
432
450
  implicitImports map[string]bool
451
+ implicitRuntime map[string]bool
433
452
  }
434
453
 
435
454
  func (o *LoweringOwner) analyzeLocalFileReferences(
@@ -444,35 +463,68 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
444
463
  reservedNames: make(map[string]bool),
445
464
  aliases: make(map[types.Object]string),
446
465
  aliasSources: make(map[string]string),
466
+ runtimeAliases: make(map[string]bool),
447
467
  implicitImports: make(map[string]bool),
468
+ implicitRuntime: make(map[string]bool),
448
469
  }
449
470
  seenObjects := make(map[types.Object]bool)
450
471
  seenTypes := make(map[types.Type]bool)
451
472
  var addTypeDeps func(typ types.Type)
452
- var addObject func(obj types.Object)
453
- addObject = func(obj types.Object) {
454
- if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != semPkg.pkgPath {
473
+ var addRuntimeTypeDeps func(typ types.Type)
474
+ var addRuntimeTypeOwnerDeps func(typ types.Type)
475
+ var addObject func(obj types.Object, runtime bool)
476
+ addObject = func(obj types.Object, runtime bool) {
477
+ if obj == nil || obj.Pkg() == nil {
455
478
  return
456
479
  }
457
- if seenObjects[obj] {
480
+ if obj.Pkg().Path() != semPkg.pkgPath {
481
+ if runtime {
482
+ analysis.implicitImports[obj.Pkg().Path()] = true
483
+ analysis.implicitRuntime[obj.Pkg().Path()] = true
484
+ }
458
485
  return
459
486
  }
460
- seenObjects[obj] = true
461
487
  declFile := declFiles[obj]
488
+ if declFile == "" {
489
+ if fn, ok := obj.(*types.Func); ok {
490
+ if decl := functionDeclForObject(semPkg, fn); decl != nil {
491
+ declFile = sourcePos(semPkg.source, decl.Pos()).file
492
+ }
493
+ }
494
+ }
462
495
  if declFile != "" && declFile != sourcePath {
463
496
  outputName := outputNames[declFile]
464
497
  if outputName != "" {
465
498
  alias := "__goscript_" + safeIdentifier(strings.TrimSuffix(outputName, ".gs.ts"))
466
499
  analysis.aliases[obj] = alias
467
500
  analysis.aliasSources[alias] = "./" + outputName
501
+ if runtime {
502
+ analysis.runtimeAliases[alias] = true
503
+ }
468
504
  }
469
505
  }
506
+ if runtime {
507
+ if alias := analysis.aliases[obj]; alias != "" {
508
+ analysis.runtimeAliases[alias] = true
509
+ }
510
+ }
511
+ if seenObjects[obj] {
512
+ return
513
+ }
514
+ seenObjects[obj] = true
470
515
  switch typed := obj.(type) {
471
516
  case *types.TypeName:
472
517
  addTypeDeps(typed.Type())
518
+ if named, ok := types.Unalias(typed.Type()).(*types.Named); ok {
519
+ if structType := structUnderlyingType(named); structType != nil {
520
+ for field := range structType.Fields() {
521
+ addRuntimeTypeDeps(field.Type())
522
+ }
523
+ }
524
+ }
473
525
  if named, ok := types.Unalias(typed.Type()).(*types.Named); ok {
474
526
  for method := range named.Methods() {
475
- addObject(method)
527
+ addObject(method, false)
476
528
  }
477
529
  }
478
530
  case *types.Var:
@@ -515,7 +567,7 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
515
567
  addTypeDeps(alias.Rhs())
516
568
  return
517
569
  }
518
- addObject(alias.Obj())
570
+ addObject(alias.Obj(), false)
519
571
  if args := alias.TypeArgs(); args != nil {
520
572
  for t := range args.Types() {
521
573
  addTypeDeps(t)
@@ -534,7 +586,7 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
534
586
  }
535
587
  return
536
588
  }
537
- addObject(named.Obj())
589
+ addObject(named.Obj(), false)
538
590
  if args := named.TypeArgs(); args != nil {
539
591
  for t := range args.Types() {
540
592
  addTypeDeps(t)
@@ -580,8 +632,93 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
580
632
  }
581
633
  }
582
634
  }
635
+ addRuntimeTypeDeps = func(typ types.Type) {
636
+ if typ == nil {
637
+ return
638
+ }
639
+ if alias, ok := typ.(*types.Alias); ok {
640
+ addObject(alias.Obj(), true)
641
+ if args := alias.TypeArgs(); args != nil {
642
+ for t := range args.Types() {
643
+ addRuntimeTypeDeps(t)
644
+ }
645
+ }
646
+ addRuntimeTypeDeps(alias.Rhs())
647
+ return
648
+ }
649
+ if named, ok := types.Unalias(typ).(*types.Named); ok {
650
+ addObject(named.Obj(), true)
651
+ for method := range named.Methods() {
652
+ addObject(method, true)
653
+ }
654
+ methodSet := types.NewMethodSet(types.NewPointer(named))
655
+ for method := range methodSet.Methods() {
656
+ addObject(method.Obj(), true)
657
+ }
658
+ if args := named.TypeArgs(); args != nil {
659
+ for t := range args.Types() {
660
+ addRuntimeTypeDeps(t)
661
+ }
662
+ }
663
+ return
664
+ }
665
+ switch typed := types.Unalias(typ).Underlying().(type) {
666
+ case *types.Pointer:
667
+ addRuntimeTypeDeps(typed.Elem())
668
+ case *types.Slice:
669
+ addRuntimeTypeDeps(typed.Elem())
670
+ case *types.Array:
671
+ addRuntimeTypeDeps(typed.Elem())
672
+ case *types.Map:
673
+ addRuntimeTypeDeps(typed.Key())
674
+ addRuntimeTypeDeps(typed.Elem())
675
+ case *types.Chan:
676
+ addRuntimeTypeDeps(typed.Elem())
677
+ }
678
+ }
679
+ addRuntimeTypeOwnerDeps = func(typ types.Type) {
680
+ if typ == nil {
681
+ return
682
+ }
683
+ if alias, ok := typ.(*types.Alias); ok {
684
+ addObject(alias.Obj(), true)
685
+ if args := alias.TypeArgs(); args != nil {
686
+ for t := range args.Types() {
687
+ addRuntimeTypeOwnerDeps(t)
688
+ }
689
+ }
690
+ addRuntimeTypeOwnerDeps(alias.Rhs())
691
+ return
692
+ }
693
+ if named, ok := types.Unalias(typ).(*types.Named); ok {
694
+ addObject(named.Obj(), true)
695
+ if args := named.TypeArgs(); args != nil {
696
+ for t := range args.Types() {
697
+ addRuntimeTypeOwnerDeps(t)
698
+ }
699
+ }
700
+ return
701
+ }
702
+ switch typed := types.Unalias(typ).Underlying().(type) {
703
+ case *types.Pointer:
704
+ addRuntimeTypeOwnerDeps(typed.Elem())
705
+ case *types.Slice:
706
+ addRuntimeTypeOwnerDeps(typed.Elem())
707
+ case *types.Array:
708
+ addRuntimeTypeOwnerDeps(typed.Elem())
709
+ case *types.Map:
710
+ addRuntimeTypeOwnerDeps(typed.Key())
711
+ addRuntimeTypeOwnerDeps(typed.Elem())
712
+ case *types.Chan:
713
+ addRuntimeTypeOwnerDeps(typed.Elem())
714
+ }
715
+ }
583
716
  inspect := func(node ast.Node) bool {
584
717
  switch typed := node.(type) {
718
+ case *ast.ValueSpec:
719
+ if len(typed.Values) == 0 && typed.Type != nil {
720
+ addRuntimeTypeDeps(semPkg.source.TypesInfo.TypeOf(typed.Type))
721
+ }
585
722
  case *ast.Ident:
586
723
  if obj := semPkg.source.TypesInfo.Defs[typed]; obj != nil {
587
724
  if _, ok := obj.(*types.PkgName); !ok {
@@ -591,18 +728,46 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
591
728
  }
592
729
  }
593
730
  }
594
- addObject(semPkg.source.TypesInfo.Uses[typed])
731
+ if tv, ok := semPkg.source.TypesInfo.Types[typed]; ok && tv.IsValue() {
732
+ addObject(semPkg.source.TypesInfo.Uses[typed], true)
733
+ }
595
734
  addTypeDeps(semPkg.source.TypesInfo.TypeOf(typed))
596
735
  case *ast.SelectorExpr:
597
736
  if selection := semPkg.source.TypesInfo.Selections[typed]; selection != nil {
598
- addObject(selection.Obj())
737
+ switch selection.Kind() {
738
+ case types.FieldVal, types.MethodVal, types.MethodExpr:
739
+ addObject(selection.Obj(), true)
740
+ if selection.Kind() != types.FieldVal {
741
+ addRuntimeTypeOwnerDeps(selection.Recv())
742
+ }
743
+ default:
744
+ addObject(selection.Obj(), false)
745
+ }
599
746
  addTypeDeps(selection.Obj().Type())
600
747
  } else if obj := semPkg.source.TypesInfo.Uses[typed.Sel]; obj != nil {
748
+ if tv, ok := semPkg.source.TypesInfo.Types[typed]; ok && tv.IsValue() {
749
+ addObject(obj, true)
750
+ }
601
751
  addTypeDeps(obj.Type())
602
752
  }
603
753
  if pointer, ok := types.Unalias(semPkg.source.TypesInfo.TypeOf(typed.X)).Underlying().(*types.Pointer); ok {
604
754
  addTypeDeps(pointer.Elem())
605
755
  }
756
+ case *ast.CompositeLit:
757
+ addRuntimeTypeDeps(semPkg.source.TypesInfo.TypeOf(typed))
758
+ addCompositeInterfaceValueDeps(semPkg.source.TypesInfo, typed, addRuntimeTypeDeps)
759
+ case *ast.CallExpr:
760
+ if ident, ok := ast.Unparen(typed.Fun).(*ast.Ident); ok && ident.Name == "new" {
761
+ for _, arg := range typed.Args {
762
+ addRuntimeTypeDeps(semPkg.source.TypesInfo.TypeOf(arg))
763
+ }
764
+ }
765
+ if ident, ok := ast.Unparen(typed.Fun).(*ast.Ident); ok && ident.Name == "make" && len(typed.Args) != 0 {
766
+ addRuntimeTypeDeps(semPkg.source.TypesInfo.TypeOf(typed.Args[0]))
767
+ }
768
+ addReflectTypeForRuntimeDeps(semPkg.source.TypesInfo, typed, addRuntimeTypeDeps)
769
+ addInterfaceArgumentRuntimeDeps(semPkg.source.TypesInfo, typed, addRuntimeTypeDeps)
770
+ addRuntimeTypeDeps(semPkg.source.TypesInfo.TypeOf(typed.Fun))
606
771
  }
607
772
  return true
608
773
  }
@@ -613,6 +778,162 @@ func (o *LoweringOwner) analyzeLocalFileReferences(
613
778
  return analysis
614
779
  }
615
780
 
781
+ func addInterfaceArgumentRuntimeDeps(
782
+ info *types.Info,
783
+ call *ast.CallExpr,
784
+ addRuntimeTypeDeps func(types.Type),
785
+ ) {
786
+ if info == nil || call == nil {
787
+ return
788
+ }
789
+ signature, _ := types.Unalias(info.TypeOf(call.Fun)).(*types.Signature)
790
+ if signature == nil || signature.Params() == nil {
791
+ return
792
+ }
793
+ params := signature.Params()
794
+ for idx, arg := range call.Args {
795
+ paramIdx := idx
796
+ if signature.Variadic() && paramIdx >= params.Len()-1 {
797
+ paramIdx = params.Len() - 1
798
+ }
799
+ if paramIdx < 0 || paramIdx >= params.Len() {
800
+ continue
801
+ }
802
+ paramType := params.At(paramIdx).Type()
803
+ if signature.Variadic() && idx >= params.Len()-1 {
804
+ if slice, ok := types.Unalias(paramType).Underlying().(*types.Slice); ok {
805
+ paramType = slice.Elem()
806
+ }
807
+ }
808
+ if typeIsInterface(paramType) {
809
+ addRuntimeTypeDeps(info.TypeOf(arg))
810
+ }
811
+ }
812
+ }
813
+
814
+ func addReflectTypeForRuntimeDeps(
815
+ info *types.Info,
816
+ call *ast.CallExpr,
817
+ addRuntimeTypeDeps func(types.Type),
818
+ ) {
819
+ if info == nil || call == nil || !isReflectTypeForExpr(info, call.Fun) {
820
+ return
821
+ }
822
+ switch typed := ast.Unparen(call.Fun).(type) {
823
+ case *ast.IndexExpr:
824
+ addRuntimeTypeDeps(info.TypeOf(typed.Index))
825
+ case *ast.IndexListExpr:
826
+ for _, index := range typed.Indices {
827
+ addRuntimeTypeDeps(info.TypeOf(index))
828
+ }
829
+ }
830
+ }
831
+
832
+ func isReflectTypeForExpr(info *types.Info, expr ast.Expr) bool {
833
+ var base ast.Expr
834
+ switch typed := ast.Unparen(expr).(type) {
835
+ case *ast.IndexExpr:
836
+ base = typed.X
837
+ case *ast.IndexListExpr:
838
+ base = typed.X
839
+ default:
840
+ return false
841
+ }
842
+ selector, ok := ast.Unparen(base).(*ast.SelectorExpr)
843
+ if !ok || selector.Sel.Name != "TypeFor" {
844
+ return false
845
+ }
846
+ ident, ok := ast.Unparen(selector.X).(*ast.Ident)
847
+ if !ok {
848
+ return false
849
+ }
850
+ pkgName, _ := info.Uses[ident].(*types.PkgName)
851
+ return pkgName != nil && pkgName.Imported() != nil && pkgName.Imported().Path() == "reflect"
852
+ }
853
+
854
+ func addCompositeInterfaceValueDeps(
855
+ info *types.Info,
856
+ lit *ast.CompositeLit,
857
+ addRuntimeTypeDeps func(types.Type),
858
+ ) {
859
+ if info == nil || lit == nil {
860
+ return
861
+ }
862
+ typ := types.Unalias(info.TypeOf(lit))
863
+ if pointer, ok := typ.Underlying().(*types.Pointer); ok {
864
+ typ = types.Unalias(pointer.Elem())
865
+ }
866
+ switch typed := typ.Underlying().(type) {
867
+ case *types.Array:
868
+ addCompositeElementsRuntimeDeps(info, lit.Elts, typed.Elem(), addRuntimeTypeDeps)
869
+ case *types.Slice:
870
+ addCompositeElementsRuntimeDeps(info, lit.Elts, typed.Elem(), addRuntimeTypeDeps)
871
+ case *types.Map:
872
+ for _, elt := range lit.Elts {
873
+ keyValue, ok := elt.(*ast.KeyValueExpr)
874
+ if !ok {
875
+ continue
876
+ }
877
+ if typeIsInterface(typed.Key()) {
878
+ addRuntimeTypeDeps(info.TypeOf(keyValue.Key))
879
+ }
880
+ if typeIsInterface(typed.Elem()) {
881
+ addRuntimeTypeDeps(info.TypeOf(keyValue.Value))
882
+ }
883
+ }
884
+ case *types.Struct:
885
+ nextField := 0
886
+ for _, elt := range lit.Elts {
887
+ fieldIdx := nextField
888
+ value := elt
889
+ if keyValue, ok := elt.(*ast.KeyValueExpr); ok {
890
+ value = keyValue.Value
891
+ if ident, ok := keyValue.Key.(*ast.Ident); ok {
892
+ for idx := range typed.NumFields() {
893
+ if typed.Field(idx).Name() == ident.Name {
894
+ fieldIdx = idx
895
+ break
896
+ }
897
+ }
898
+ }
899
+ } else {
900
+ nextField++
901
+ }
902
+ if fieldIdx < 0 || fieldIdx >= typed.NumFields() {
903
+ continue
904
+ }
905
+ if typeIsInterface(typed.Field(fieldIdx).Type()) {
906
+ addRuntimeTypeDeps(info.TypeOf(value))
907
+ }
908
+ }
909
+ }
910
+ }
911
+
912
+ func addCompositeElementsRuntimeDeps(
913
+ info *types.Info,
914
+ elements []ast.Expr,
915
+ elemType types.Type,
916
+ addRuntimeTypeDeps func(types.Type),
917
+ ) {
918
+ if !typeIsInterface(elemType) {
919
+ return
920
+ }
921
+ for _, elt := range elements {
922
+ if keyValue, ok := elt.(*ast.KeyValueExpr); ok {
923
+ elt = keyValue.Value
924
+ }
925
+ addRuntimeTypeDeps(info.TypeOf(elt))
926
+ }
927
+ }
928
+
929
+ func typeIsInterface(typ types.Type) bool {
930
+ if typ == nil {
931
+ return false
932
+ }
933
+ _, ok := types.Unalias(typ).Underlying().(*types.Interface)
934
+ return ok
935
+ }
936
+
616
937
  func safeIdentifier(value string) string {
617
938
  var b strings.Builder
618
939
  for idx, r := range value {
@@ -803,7 +1124,7 @@ func isConstGenDecl(decl ast.Decl) bool {
803
1124
  }
804
1125
 
805
1126
  func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([]loweredDecl, []Diagnostic) {
806
- var decls []loweredDecl
1127
+ decls := make([]loweredDecl, 0, len(decl.Specs))
807
1128
  var diagnostics []Diagnostic
808
1129
  for _, spec := range decl.Specs {
809
1130
  switch typed := spec.(type) {
@@ -868,8 +1189,8 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
868
1189
  lazy := ctx.topLevel && ctx.lazyPackageVars[obj]
869
1190
  code := keyword + " " + declName + ": " + variableType + " = " + value
870
1191
  if lazy {
871
- keyword = "let"
872
- code = "let " + declName + ": " + variableType + " = undefined as unknown as " + variableType
1192
+ keyword = "var"
1193
+ code = "var " + declName + ": " + variableType
873
1194
  }
874
1195
  indexExport := ""
875
1196
  if ctx.topLevel && name.Name != "_" {
@@ -881,19 +1202,27 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
881
1202
  decls = append(decls, loweredDecl{code: code, indexExport: indexExport})
882
1203
  if lazy {
883
1204
  getterName := packageVarGetterName(name.Name)
1205
+ initName := packageVarInitName(name.Name)
1206
+ initIndexExport := ""
1207
+ if ast.IsExported(name.Name) {
1208
+ initIndexExport = initName
1209
+ }
884
1210
  getterCode := "export function " + getterName + "(): " + variableType + " {\n\t"
885
1211
  if strings.Contains(value, "await ") {
886
- initName := packageVarInitName(name.Name)
887
- initCode := "async function " + initName + "(): globalThis.Promise<void> {\n\t" +
1212
+ initCode := "export async function " + initName + "(): globalThis.Promise<void> {\n\t" +
888
1213
  "if (((" + declName + ") as any) === undefined) {\n\t\t" +
889
1214
  declName + " = " + value + "\n\t}\n}"
890
- decls = append(decls, loweredDecl{code: initCode})
1215
+ decls = append(decls, loweredDecl{code: initCode, indexExport: initIndexExport})
891
1216
  decls = append(decls, loweredDecl{packageInitCall: initName + "()"})
892
1217
  getterCode += "if (((" + declName + ") as any) === undefined) {\n\t\t" +
893
1218
  "throw new Error(" + strconv.Quote("goscript package variable "+name.Name+" read before initialization") + ")\n\t}\n"
894
1219
  } else {
1220
+ initCode := "export function " + initName + "(): void {\n\t" +
1221
+ "if (((" + declName + ") as any) === undefined) {\n\t\t" +
1222
+ declName + " = " + value + "\n\t}\n}"
1223
+ decls = append(decls, loweredDecl{code: initCode, indexExport: initIndexExport})
895
1224
  getterCode += "if (((" + declName + ") as any) === undefined) {\n\t\t" +
896
- declName + " = " + value + "\n\t}\n"
1225
+ initName + "()\n\t}\n"
897
1226
  }
898
1227
  getterCode += "\treturn " + declName + "\n}"
899
1228
  getterIndexExport := ""
@@ -907,10 +1236,15 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
907
1236
  setterType := o.tsPackageVarSetterValueTypeFor(ctx, obj.Type())
908
1237
  setterTarget := declName
909
1238
  if ctx.model.needsVarRef[obj] {
910
- setterTarget += ".value"
1239
+ if lazy {
1240
+ setterTarget = packageVarGetterName(name.Name) + "().value"
1241
+ } else {
1242
+ setterTarget += ".value"
1243
+ }
911
1244
  }
912
- setterCode := "export function " + setterName + "(value: " + setterType + "): void {\n\t" +
913
- setterTarget + " = value\n}"
1245
+ setterValue := "__goscriptValue"
1246
+ setterCode := "export function " + setterName + "(" + setterValue + ": " + setterType + "): void {\n\t" +
1247
+ setterTarget + " = " + setterValue + "\n}"
914
1248
  setterIndexExport := ""
915
1249
  if ast.IsExported(name.Name) {
916
1250
  setterIndexExport = setterName
@@ -964,6 +1298,9 @@ func initializerMayHaveRuntimeEffects(ctx lowerFileContext, expr ast.Expr) bool
964
1298
  }
965
1299
  switch typed := node.(type) {
966
1300
  case *ast.CallExpr:
1301
+ if isEffectFreePackageInitializerCall(ctx, typed) {
1302
+ return true
1303
+ }
967
1304
  if callTargetSignature(ctx, typed.Fun) != nil {
968
1305
  hasEffects = true
969
1306
  return false
@@ -979,11 +1316,93 @@ func initializerMayHaveRuntimeEffects(ctx lowerFileContext, expr ast.Expr) bool
979
1316
  return hasEffects
980
1317
  }
981
1318
 
1319
+ func isEffectFreePackageInitializerCall(ctx lowerFileContext, call *ast.CallExpr) bool {
1320
+ if call == nil {
1321
+ return false
1322
+ }
1323
+ if isEffectFreePackageInitializerBuiltin(ctx, call.Fun) {
1324
+ return true
1325
+ }
1326
+ if isReflectTypeOfCall(ctx, call) {
1327
+ return true
1328
+ }
1329
+ if isReflectTypeForCall(ctx, call) {
1330
+ return true
1331
+ }
1332
+ if isMathBigNewIntCall(ctx, call) {
1333
+ return true
1334
+ }
1335
+ selector, ok := ast.Unparen(call.Fun).(*ast.SelectorExpr)
1336
+ if !ok || selector.Sel.Name != "Elem" {
1337
+ return false
1338
+ }
1339
+ receiver, ok := ast.Unparen(selector.X).(*ast.CallExpr)
1340
+ return ok && isReflectTypeOfCall(ctx, receiver)
1341
+ }
1342
+
1343
+ func isEffectFreePackageInitializerBuiltin(ctx lowerFileContext, expr ast.Expr) bool {
1344
+ ident, ok := expr.(*ast.Ident)
1345
+ if !ok {
1346
+ return false
1347
+ }
1348
+ if ident.Name != "make" && ident.Name != "new" {
1349
+ return false
1350
+ }
1351
+ _, ok = objectForIdent(ctx, ident).(*types.Builtin)
1352
+ return ok
1353
+ }
1354
+
1355
+ func isReflectTypeOfCall(ctx lowerFileContext, call *ast.CallExpr) bool {
1356
+ selector, ok := ast.Unparen(call.Fun).(*ast.SelectorExpr)
1357
+ if !ok || selector.Sel.Name != "TypeOf" {
1358
+ return false
1359
+ }
1360
+ ident, ok := ast.Unparen(selector.X).(*ast.Ident)
1361
+ if !ok {
1362
+ return false
1363
+ }
1364
+ pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName)
1365
+ return pkgName != nil && pkgName.Imported() != nil && pkgName.Imported().Path() == "reflect"
1366
+ }
1367
+
1368
+ func isReflectTypeForCall(ctx lowerFileContext, call *ast.CallExpr) bool {
1369
+ fun := ast.Unparen(call.Fun)
1370
+ switch typed := fun.(type) {
1371
+ case *ast.IndexExpr:
1372
+ fun = ast.Unparen(typed.X)
1373
+ case *ast.IndexListExpr:
1374
+ fun = ast.Unparen(typed.X)
1375
+ }
1376
+ selector, ok := fun.(*ast.SelectorExpr)
1377
+ if !ok || selector.Sel.Name != "TypeFor" {
1378
+ return false
1379
+ }
1380
+ ident, ok := ast.Unparen(selector.X).(*ast.Ident)
1381
+ if !ok {
1382
+ return false
1383
+ }
1384
+ pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName)
1385
+ return pkgName != nil && pkgName.Imported() != nil && pkgName.Imported().Path() == "reflect"
1386
+ }
1387
+
1388
+ func isMathBigNewIntCall(ctx lowerFileContext, call *ast.CallExpr) bool {
1389
+ selector, ok := ast.Unparen(call.Fun).(*ast.SelectorExpr)
1390
+ if !ok || selector.Sel.Name != "NewInt" {
1391
+ return false
1392
+ }
1393
+ ident, ok := ast.Unparen(selector.X).(*ast.Ident)
1394
+ if !ok {
1395
+ return false
1396
+ }
1397
+ pkgName, _ := objectForIdent(ctx, ident).(*types.PkgName)
1398
+ return pkgName != nil && pkgName.Imported() != nil && pkgName.Imported().Path() == "math/big"
1399
+ }
1400
+
982
1401
  func packageDeclFiles(semPkg *semanticPackage) map[types.Object]string {
983
1402
  if semPkg == nil || semPkg.source == nil {
984
1403
  return nil
985
1404
  }
986
- declFiles := make(map[types.Object]string)
1405
+ declFiles := make(map[types.Object]string, len(semPkg.declarations))
987
1406
  for _, decl := range semPkg.declarations {
988
1407
  if decl.object != nil && decl.position.file != "" {
989
1408
  declFiles[decl.object] = decl.position.file
@@ -1012,6 +1431,7 @@ func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage, declFiles map[t
1012
1431
  for idx, obj := range semPkg.initOrder {
1013
1432
  varOrder[obj] = idx
1014
1433
  }
1434
+ funcRefs := packageVarsReferencedFromOtherFileTopLevelCalls(semPkg, declFiles)
1015
1435
  lazy := make(map[types.Object]bool)
1016
1436
  for idx, file := range semPkg.source.Syntax {
1017
1437
  sourcePath := sourceFilePath(semPkg, idx, file)
@@ -1048,6 +1468,12 @@ func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage, declFiles map[t
1048
1468
  if valueIdx >= len(valueSpec.Values) &&
1049
1469
  zeroValueReferencesOtherFileObject(semPkg, declFiles, sourcePath, obj.Type()) {
1050
1470
  lazy[obj] = true
1471
+ continue
1472
+ }
1473
+ if funcRefs[obj] &&
1474
+ (valueIdx >= len(valueSpec.Values) ||
1475
+ !initializerMayHaveRuntimeEffects(lowerFileContext{semPkg: semPkg}, valueSpec.Values[valueIdx])) {
1476
+ lazy[obj] = true
1051
1477
  }
1052
1478
  }
1053
1479
  }
@@ -1056,6 +1482,178 @@ func (o *LoweringOwner) lazyPackageVars(semPkg *semanticPackage, declFiles map[t
1056
1482
  return lazy
1057
1483
  }
1058
1484
 
1485
+ func packageVarsReferencedFromOtherFileTopLevelCalls(
1486
+ semPkg *semanticPackage,
1487
+ declFiles map[types.Object]string,
1488
+ ) map[*types.Var]bool {
1489
+ refs := make(map[*types.Var]bool)
1490
+ if semPkg == nil || semPkg.source == nil || semPkg.source.TypesInfo == nil {
1491
+ return refs
1492
+ }
1493
+ var collectFuncRefs func(rootSource string, fn *types.Func, seen map[*types.Func]bool)
1494
+ collectFuncRefs = func(rootSource string, fn *types.Func, seen map[*types.Func]bool) {
1495
+ if fn == nil || seen[fn] {
1496
+ return
1497
+ }
1498
+ seen[fn] = true
1499
+ decl := functionDeclForObject(semPkg, fn)
1500
+ if decl == nil || decl.Body == nil {
1501
+ return
1502
+ }
1503
+ ast.Inspect(decl.Body, func(node ast.Node) bool {
1504
+ switch typed := node.(type) {
1505
+ case *ast.Ident:
1506
+ obj, _ := semPkg.source.TypesInfo.Uses[typed].(*types.Var)
1507
+ if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != semPkg.pkgPath {
1508
+ return true
1509
+ }
1510
+ if declFiles[obj] != "" && declFiles[obj] != rootSource {
1511
+ refs[obj] = true
1512
+ }
1513
+ case *ast.CallExpr:
1514
+ called := calledFunction(semPkg.source, typed.Fun)
1515
+ if called != nil && called.Pkg() != nil && called.Pkg().Path() == semPkg.pkgPath {
1516
+ collectFuncRefs(rootSource, called, seen)
1517
+ }
1518
+ }
1519
+ return true
1520
+ })
1521
+ }
1522
+ for _, file := range semPkg.source.Syntax {
1523
+ sourcePath := sourcePos(semPkg.source, file.Pos()).file
1524
+ for _, decl := range file.Decls {
1525
+ switch typed := decl.(type) {
1526
+ case *ast.GenDecl:
1527
+ if typed.Tok != token.VAR {
1528
+ continue
1529
+ }
1530
+ for _, spec := range typed.Specs {
1531
+ valueSpec, ok := spec.(*ast.ValueSpec)
1532
+ if !ok {
1533
+ continue
1534
+ }
1535
+ for _, value := range valueSpec.Values {
1536
+ collectTopLevelRefs(semPkg, declFiles, refs, sourcePath, value, collectFuncRefs)
1537
+ }
1538
+ }
1539
+ case *ast.FuncDecl:
1540
+ if typed.Name.Name == "init" && typed.Body != nil {
1541
+ collectTopLevelRefs(semPkg, declFiles, refs, sourcePath, typed.Body, collectFuncRefs)
1542
+ }
1543
+ }
1544
+ }
1545
+ }
1546
+ return refs
1547
+ }
1548
+
1549
+ func collectTopLevelRefs(
1550
+ semPkg *semanticPackage,
1551
+ declFiles map[types.Object]string,
1552
+ refs map[*types.Var]bool,
1553
+ sourcePath string,
1554
+ node ast.Node,
1555
+ collectFuncRefs func(string, *types.Func, map[*types.Func]bool),
1556
+ ) {
1557
+ ast.Inspect(node, func(node ast.Node) bool {
1558
+ switch typed := node.(type) {
1559
+ case *ast.Ident:
1560
+ obj, _ := semPkg.source.TypesInfo.Uses[typed].(*types.Var)
1561
+ if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != semPkg.pkgPath {
1562
+ return true
1563
+ }
1564
+ if declFiles[obj] != "" && declFiles[obj] != sourcePath {
1565
+ refs[obj] = true
1566
+ }
1567
+ case *ast.CallExpr:
1568
+ called := calledFunction(semPkg.source, typed.Fun)
1569
+ if called == nil || called.Pkg() == nil || called.Pkg().Path() != semPkg.pkgPath {
1570
+ return true
1571
+ }
1572
+ collectFuncRefs(sourcePath, called, make(map[*types.Func]bool))
1573
+ }
1574
+ return true
1575
+ })
1576
+ }
1577
+
1578
+ func (o *LoweringOwner) packageVarIsLazy(ctx lowerFileContext, obj *types.Var) bool {
1579
+ if obj == nil {
1580
+ return false
1581
+ }
1582
+ if ctx.lazyPackageVars[obj] {
1583
+ return true
1584
+ }
1585
+ if ctx.model == nil || obj.Pkg() == nil {
1586
+ return false
1587
+ }
1588
+ semPkg := ctx.model.packages[obj.Pkg().Path()]
1589
+ if semPkg == nil {
1590
+ return false
1591
+ }
1592
+ for lazyObj := range o.lazyPackageVars(semPkg, packageDeclFiles(semPkg)) {
1593
+ if lazyObj != nil && lazyObj.Name() == obj.Name() &&
1594
+ lazyObj.Pkg() != nil && lazyObj.Pkg().Path() == obj.Pkg().Path() {
1595
+ return true
1596
+ }
1597
+ }
1598
+ return false
1599
+ }
1600
+
1601
+ func (o *LoweringOwner) packageVarNameIsLazy(ctx lowerFileContext, pkgPath, name string) bool {
1602
+ if ctx.model == nil || pkgPath == "" || name == "" {
1603
+ return false
1604
+ }
1605
+ semPkg := ctx.model.packages[pkgPath]
1606
+ if semPkg == nil {
1607
+ return false
1608
+ }
1609
+ for lazyObj := range o.lazyPackageVars(semPkg, packageDeclFiles(semPkg)) {
1610
+ if lazyObj != nil && lazyObj.Name() == name {
1611
+ return true
1612
+ }
1613
+ }
1614
+ return false
1615
+ }
1616
+
1617
+ func (o *LoweringOwner) packageVarHasAsyncLazyInit(ctx lowerFileContext, obj types.Object) bool {
1618
+ varObj, _ := obj.(*types.Var)
1619
+ if varObj == nil || varObj.Pkg() == nil {
1620
+ return false
1621
+ }
1622
+ return o.packageVarNameHasAsyncLazyInit(ctx, varObj.Pkg().Path(), varObj.Name())
1623
+ }
1624
+
1625
+ func (o *LoweringOwner) packageVarNameHasAsyncLazyInit(ctx lowerFileContext, pkgPath, name string) bool {
1626
+ if ctx.model == nil || pkgPath == "" || name == "" {
1627
+ return false
1628
+ }
1629
+ semPkg := ctx.model.packages[pkgPath]
1630
+ if semPkg == nil || semPkg.source == nil {
1631
+ return false
1632
+ }
1633
+ initCtx := lowerFileContext{model: ctx.model, semPkg: semPkg, topLevel: true}
1634
+ for _, file := range semPkg.source.Syntax {
1635
+ for _, decl := range file.Decls {
1636
+ genDecl, ok := decl.(*ast.GenDecl)
1637
+ if !ok || genDecl.Tok != token.VAR {
1638
+ continue
1639
+ }
1640
+ for _, spec := range genDecl.Specs {
1641
+ valueSpec, ok := spec.(*ast.ValueSpec)
1642
+ if !ok {
1643
+ continue
1644
+ }
1645
+ for idx, ident := range valueSpec.Names {
1646
+ if ident.Name != name || idx >= len(valueSpec.Values) {
1647
+ continue
1648
+ }
1649
+ return o.topLevelInitializerNeedsAwait(initCtx, valueSpec.Values[idx])
1650
+ }
1651
+ }
1652
+ }
1653
+ }
1654
+ return false
1655
+ }
1656
+
1059
1657
  func initializerReferencesLaterPackageVar(
1060
1658
  semPkg *semanticPackage,
1061
1659
  varOrder map[types.Object]int,
@@ -1278,7 +1876,7 @@ func (o *LoweringOwner) lowerTupleValueSpec(
1278
1876
  tupleExpr := tempName
1279
1877
  if lazyTuple {
1280
1878
  tupleGetterName := packageVarGetterName(tempName)
1281
- decls = append(decls, loweredDecl{code: "let " + tempName + ": any = undefined as any"})
1879
+ decls = append(decls, loweredDecl{code: "var " + tempName + ": any = undefined as any"})
1282
1880
  decls = append(decls, loweredDecl{code: "function " + tupleGetterName + "(): any {\n\t" +
1283
1881
  "if (((" + tempName + ") as any) === undefined) {\n\t\t" +
1284
1882
  tempName + " = " + right + "\n\t}\n\treturn " + tempName + "\n}"})
@@ -1303,8 +1901,8 @@ func (o *LoweringOwner) lowerTupleValueSpec(
1303
1901
  code := keyword + " " + o.lowerIdent(ctx, name, true) + ": " + variableType + " = " + value
1304
1902
  lazy := lazyTuple || ctx.topLevel && ctx.lazyPackageVars[obj]
1305
1903
  if lazy {
1306
- keyword = "let"
1307
- code = "let " + o.lowerIdent(ctx, name, true) + ": " + variableType + " = undefined as unknown as " + variableType
1904
+ keyword = "var"
1905
+ code = "var " + o.lowerIdent(ctx, name, true) + ": " + variableType + " = undefined as unknown as " + variableType
1308
1906
  }
1309
1907
  indexExport := ""
1310
1908
  if ctx.topLevel {
@@ -1364,6 +1962,13 @@ func lowerLargeIntegerConstantValue(value constant.Value) (string, bool) {
1364
1962
  return value.ExactString(), true
1365
1963
  }
1366
1964
 
1965
+ func lowerWideIntegerConstantValue(value constant.Value) (string, bool) {
1966
+ if value == nil || value.Kind() != constant.Int || constant.BitLen(value) <= 53 {
1967
+ return "", false
1968
+ }
1969
+ return value.ExactString(), true
1970
+ }
1971
+
1367
1972
  func lowerConstantStringByteSlice(ctx lowerFileContext, expr ast.Expr) (string, bool) {
1368
1973
  value := ctx.semPkg.source.TypesInfo.Types[unwrapParenExpr(expr)].Value
1369
1974
  if value == nil || value.Kind() != constant.String {
@@ -1397,46 +2002,229 @@ func goEmbedPatterns(groups ...*ast.CommentGroup) []string {
1397
2002
  if !strings.HasPrefix(text, "go:embed") {
1398
2003
  continue
1399
2004
  }
1400
- patterns = append(patterns, strings.Fields(strings.TrimSpace(strings.TrimPrefix(text, "go:embed")))...)
2005
+ patterns = append(patterns, strings.Fields(strings.TrimSpace(strings.TrimPrefix(text, "go:embed")))...)
2006
+ }
2007
+ }
2008
+ return patterns
2009
+ }
2010
+
2011
+ func (o *LoweringOwner) lowerGoEmbedValue(
2012
+ ctx lowerFileContext,
2013
+ typ types.Type,
2014
+ patterns []string,
2015
+ ) (string, []Diagnostic) {
2016
+ if isEmbedFSType(typ) {
2017
+ return o.lowerGoEmbedFSValue(ctx, patterns)
2018
+ }
2019
+ if len(patterns) != 1 {
2020
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2021
+ }
2022
+ cleanPattern, diagnostics := cleanGoEmbedFilePattern(ctx, patterns[0])
2023
+ if len(diagnostics) != 0 {
2024
+ return "", diagnostics
2025
+ }
2026
+ data, diagnostics := readGoEmbedFile(ctx, cleanPattern)
2027
+ if len(diagnostics) != 0 {
2028
+ return "", diagnostics
2029
+ }
2030
+ if isStringType(typ) {
2031
+ return strconv.Quote(string(data)), nil
2032
+ }
2033
+ if slice, ok := types.Unalias(typ).Underlying().(*types.Slice); ok && isByteType(slice.Elem()) {
2034
+ return byteSliceLiteral(data), nil
2035
+ }
2036
+ diag := loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed target type")
2037
+ diag.Detail = "target type: " + types.TypeString(typ, func(pkg *types.Package) string {
2038
+ if pkg == nil {
2039
+ return ""
2040
+ }
2041
+ return pkg.Path()
2042
+ })
2043
+ return "", []Diagnostic{diag}
2044
+ }
2045
+
2046
+ func (o *LoweringOwner) lowerGoEmbedFSValue(ctx lowerFileContext, patterns []string) (string, []Diagnostic) {
2047
+ embedAlias := ctx.importPaths["embed"]
2048
+ if embedAlias == "" {
2049
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed FS import")}
2050
+ }
2051
+ if len(patterns) == 0 {
2052
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2053
+ }
2054
+
2055
+ filesByPath := make(map[string][]byte)
2056
+ for _, pattern := range patterns {
2057
+ files, diagnostics := expandGoEmbedPattern(ctx, pattern)
2058
+ if len(diagnostics) != 0 {
2059
+ return "", diagnostics
2060
+ }
2061
+ for _, file := range files {
2062
+ filesByPath[file.path] = file.data
2063
+ }
2064
+ }
2065
+ paths := make([]string, 0, len(filesByPath))
2066
+ for path := range filesByPath {
2067
+ paths = append(paths, path)
2068
+ }
2069
+ slices.Sort(paths)
2070
+ entries := make([]string, 0, len(paths))
2071
+ for _, path := range paths {
2072
+ entries = append(entries, "["+strconv.Quote(path)+", "+byteSliceLiteral(filesByPath[path])+"]")
2073
+ }
2074
+ builtinAlias := o.runtimeOwner.BuiltinImport().Alias
2075
+ return builtinAlias + ".markAsStructValue(new " + embedAlias + ".FS(new Map<string, Uint8Array>([" + strings.Join(entries, ", ") + "])))", nil
2076
+ }
2077
+
2078
+ type goEmbedFile struct {
2079
+ path string
2080
+ data []byte
2081
+ }
2082
+
2083
+ func cleanGoEmbedFilePattern(ctx lowerFileContext, pattern string) (string, []Diagnostic) {
2084
+ cleanPattern, _, diagnostics := cleanGoEmbedPattern(ctx, pattern)
2085
+ if len(diagnostics) != 0 {
2086
+ return "", diagnostics
2087
+ }
2088
+ if strings.Contains(cleanPattern, "*") {
2089
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2090
+ }
2091
+ info, err := os.Stat(filepath.Join(filepath.Dir(ctx.sourcePath), filepath.FromSlash(cleanPattern)))
2092
+ if err != nil {
2093
+ return "", []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2094
+ }
2095
+ if info.IsDir() {
2096
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed directory target")}
2097
+ }
2098
+ return cleanPattern, nil
2099
+ }
2100
+
2101
+ func cleanGoEmbedPattern(ctx lowerFileContext, pattern string) (string, bool, []Diagnostic) {
2102
+ pattern = strings.Trim(pattern, "`\"")
2103
+ all := false
2104
+ if strings.HasPrefix(pattern, "all:") {
2105
+ all = true
2106
+ pattern = strings.TrimPrefix(pattern, "all:")
2107
+ }
2108
+ cleanPattern := path.Clean(pattern)
2109
+ if pattern == "" ||
2110
+ path.IsAbs(pattern) ||
2111
+ cleanPattern == "." ||
2112
+ cleanPattern == ".." ||
2113
+ strings.HasPrefix(cleanPattern, "../") {
2114
+ return "", false, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2115
+ }
2116
+ return cleanPattern, all, nil
2117
+ }
2118
+
2119
+ func expandGoEmbedPattern(ctx lowerFileContext, pattern string) ([]goEmbedFile, []Diagnostic) {
2120
+ cleanPattern, all, diagnostics := cleanGoEmbedPattern(ctx, pattern)
2121
+ if len(diagnostics) != 0 {
2122
+ return nil, diagnostics
2123
+ }
2124
+ pkgDir := filepath.Dir(ctx.sourcePath)
2125
+ paths := []string{filepath.Join(pkgDir, filepath.FromSlash(cleanPattern))}
2126
+ if strings.Contains(cleanPattern, "*") {
2127
+ matches, err := filepath.Glob(filepath.Join(pkgDir, filepath.FromSlash(cleanPattern)))
2128
+ if err != nil {
2129
+ return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2130
+ }
2131
+ if len(matches) == 0 {
2132
+ return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "go:embed pattern matched no files")}
2133
+ }
2134
+ paths = matches
2135
+ }
2136
+
2137
+ var files []goEmbedFile
2138
+ for _, path := range paths {
2139
+ collected, diagnostics := collectGoEmbedPath(ctx, pkgDir, path, all)
2140
+ if len(diagnostics) != 0 {
2141
+ return nil, diagnostics
2142
+ }
2143
+ files = append(files, collected...)
2144
+ }
2145
+ slices.SortFunc(files, func(a, b goEmbedFile) int {
2146
+ return cmp.Compare(a.path, b.path)
2147
+ })
2148
+ return files, nil
2149
+ }
2150
+
2151
+ func collectGoEmbedPath(ctx lowerFileContext, pkgDir, absPath string, all bool) ([]goEmbedFile, []Diagnostic) {
2152
+ info, err := os.Stat(absPath)
2153
+ if err != nil {
2154
+ return nil, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2155
+ }
2156
+ if !info.IsDir() {
2157
+ file, diagnostics := readGoEmbedAbsFile(ctx, pkgDir, absPath)
2158
+ if len(diagnostics) != 0 {
2159
+ return nil, diagnostics
2160
+ }
2161
+ return []goEmbedFile{file}, nil
2162
+ }
2163
+
2164
+ var files []goEmbedFile
2165
+ if err := filepath.WalkDir(absPath, func(path string, entry os.DirEntry, err error) error {
2166
+ if err != nil {
2167
+ return err
2168
+ }
2169
+ if path != absPath && !all && (strings.HasPrefix(entry.Name(), ".") || strings.HasPrefix(entry.Name(), "_")) {
2170
+ if entry.IsDir() {
2171
+ return filepath.SkipDir
2172
+ }
2173
+ return nil
2174
+ }
2175
+ if entry.IsDir() {
2176
+ return nil
2177
+ }
2178
+ file, diagnostics := readGoEmbedAbsFile(ctx, pkgDir, path)
2179
+ if len(diagnostics) != 0 {
2180
+ return fmt.Errorf("%s", diagnostics[0].Detail)
1401
2181
  }
2182
+ files = append(files, file)
2183
+ return nil
2184
+ }); err != nil {
2185
+ return nil, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
1402
2186
  }
1403
- return patterns
2187
+ if len(files) == 0 {
2188
+ return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "go:embed directory matched no files")}
2189
+ }
2190
+ return files, nil
1404
2191
  }
1405
2192
 
1406
- func (o *LoweringOwner) lowerGoEmbedValue(
1407
- ctx lowerFileContext,
1408
- typ types.Type,
1409
- patterns []string,
1410
- ) (string, []Diagnostic) {
1411
- if len(patterns) != 1 {
1412
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2193
+ func readGoEmbedFile(ctx lowerFileContext, cleanPattern string) ([]byte, []Diagnostic) {
2194
+ file, diagnostics := readGoEmbedAbsFile(ctx, filepath.Dir(ctx.sourcePath), filepath.Join(filepath.Dir(ctx.sourcePath), filepath.FromSlash(cleanPattern)))
2195
+ if len(diagnostics) != 0 {
2196
+ return nil, diagnostics
1413
2197
  }
1414
- pattern := strings.Trim(patterns[0], "`\"")
1415
- cleanPattern := path.Clean(pattern)
1416
- if pattern == "" ||
1417
- strings.Contains(pattern, "*") ||
1418
- path.IsAbs(pattern) ||
1419
- cleanPattern == "." ||
1420
- cleanPattern == ".." ||
1421
- strings.HasPrefix(cleanPattern, "../") {
1422
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2198
+ return file.data, nil
2199
+ }
2200
+
2201
+ func readGoEmbedAbsFile(ctx lowerFileContext, pkgDir, absPath string) (goEmbedFile, []Diagnostic) {
2202
+ relPath, err := filepath.Rel(pkgDir, absPath)
2203
+ if err != nil {
2204
+ return goEmbedFile{}, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
1423
2205
  }
1424
- data, err := os.ReadFile(filepath.Join(filepath.Dir(ctx.sourcePath), filepath.FromSlash(cleanPattern)))
2206
+ data, err := os.ReadFile(absPath)
1425
2207
  if err != nil {
1426
- return "", []Diagnostic{{
1427
- Severity: DiagnosticSeverityError,
1428
- Code: "goscript/lowering:embed",
1429
- Message: "failed to read go:embed file",
1430
- Detail: ctx.semPkg.pkgPath + ": " + err.Error(),
1431
- }}
2208
+ return goEmbedFile{}, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
1432
2209
  }
1433
- if isStringType(typ) {
1434
- return strconv.Quote(string(data)), nil
2210
+ return goEmbedFile{path: filepath.ToSlash(relPath), data: data}, nil
2211
+ }
2212
+
2213
+ func goEmbedReadDiagnostic(ctx lowerFileContext, err error) Diagnostic {
2214
+ return Diagnostic{
2215
+ Severity: DiagnosticSeverityError,
2216
+ Code: "goscript/lowering:embed",
2217
+ Message: "failed to read go:embed file",
2218
+ Detail: ctx.semPkg.pkgPath + ": " + err.Error(),
1435
2219
  }
1436
- if slice, ok := types.Unalias(typ).Underlying().(*types.Slice); ok && isByteType(slice.Elem()) {
1437
- return byteSliceLiteral(data), nil
2220
+ }
2221
+
2222
+ func isEmbedFSType(typ types.Type) bool {
2223
+ named, _ := types.Unalias(typ).(*types.Named)
2224
+ if named == nil || named.Obj() == nil || named.Obj().Pkg() == nil {
2225
+ return false
1438
2226
  }
1439
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed target type")}
2227
+ return named.Obj().Pkg().Path() == "embed" && named.Obj().Name() == "FS"
1440
2228
  }
1441
2229
 
1442
2230
  func byteSliceLiteral(data []byte) string {
@@ -1493,12 +2281,13 @@ func (o *LoweringOwner) lowerTypeSpec(ctx lowerFileContext, spec *ast.TypeSpec)
1493
2281
  if signature, ok := named.Underlying().(*types.Signature); ok {
1494
2282
  loweredType = o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
1495
2283
  }
1496
- code := "type " + semType.name + " = " + loweredType
2284
+ typeName := safeIdentifier(semType.name)
2285
+ code := "type " + typeName + " = " + loweredType
1497
2286
  typeIndexExport := ""
1498
2287
  if ctx.topLevel {
1499
2288
  code = "export " + code
1500
2289
  if ast.IsExported(semType.name) {
1501
- typeIndexExport = semType.name
2290
+ typeIndexExport = typeName
1502
2291
  }
1503
2292
  }
1504
2293
  return loweredDecl{code: code, typeIndexExport: typeIndexExport}, nil
@@ -1506,12 +2295,13 @@ func (o *LoweringOwner) lowerTypeSpec(ctx lowerFileContext, spec *ast.TypeSpec)
1506
2295
 
1507
2296
  func (o *LoweringOwner) lowerInterfaceType(ctx lowerFileContext, semType *semanticType, iface *types.Interface) loweredDecl {
1508
2297
  iface.Complete()
1509
- code := "type " + semType.name + " = " + o.tsInterfaceType(ctx, iface)
2298
+ typeName := safeIdentifier(semType.name)
2299
+ code := "type " + typeName + " = " + o.tsInterfaceType(ctx, iface)
1510
2300
  typeIndexExport := ""
1511
2301
  if ctx.topLevel {
1512
2302
  code = "export " + code
1513
2303
  if ast.IsExported(semType.name) {
1514
- typeIndexExport = semType.name
2304
+ typeIndexExport = typeName
1515
2305
  }
1516
2306
  }
1517
2307
  code = code + "\n\n" + o.runtimeOwner.QualifiedHelper(RuntimeHelperRegisterInterfaceType) +
@@ -1599,9 +2389,10 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
1599
2389
  lowered := &loweredStruct{
1600
2390
  exported: ctx.topLevel,
1601
2391
  indexExported: ctx.topLevel && ast.IsExported(semType.name),
1602
- name: semType.name,
2392
+ name: safeIdentifier(semType.name),
1603
2393
  typeName: runtimeNamedTypeName(semType.named),
1604
2394
  cloneMethod: "clone",
2395
+ fields: make([]loweredStructField, 0, len(semType.fields)),
1605
2396
  }
1606
2397
  for idx, field := range semType.fields {
1607
2398
  structValue := isStructValueType(field.typ)
@@ -1628,9 +2419,12 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
1628
2419
 
1629
2420
  methodDecls := o.methodDeclsForType(ctx, semType.named)
1630
2421
  explicitMethods := make(map[string]bool, len(methodDecls))
1631
- for _, methodDecl := range methodDecls {
1632
- if methodDecl != nil {
1633
- explicitMethods[methodDecl.Name.Name] = true
2422
+ if len(methodDecls) != 0 {
2423
+ lowered.methods = make([]loweredFunction, 0, len(methodDecls))
2424
+ for _, methodDecl := range methodDecls {
2425
+ if methodDecl != nil {
2426
+ explicitMethods[methodDecl.Name.Name] = true
2427
+ }
1634
2428
  }
1635
2429
  }
1636
2430
  var diagnostics []Diagnostic
@@ -2434,105 +3228,113 @@ func (o *LoweringOwner) lowerStmtListAfter(
2434
3228
  ) ([]loweredStmt, []Diagnostic) {
2435
3229
  lowered := make([]loweredStmt, 0, len(stmts))
2436
3230
  var diagnostics []Diagnostic
2437
- gotoSpans := backwardGotoLabelSpans(stmts)
2438
- gotoLabels := make(map[string]bool, len(gotoSpans))
2439
- for label := range gotoSpans {
2440
- gotoLabels[label] = true
2441
- }
2442
- forwardSpans := forwardGotoLabelSpans(stmts, gotoSpans)
2443
- forwardStarts := make(map[int]forwardGotoLabelSpan, len(forwardSpans))
2444
- for label, span := range forwardSpans {
2445
- span.label = label
2446
- group := forwardStarts[span.start]
2447
- if group.forwardLabels == nil {
2448
- group.forwardLabels = make(map[string]bool)
2449
- }
2450
- group.forwardLabels[label] = true
2451
- if group.label == "" || span.labelIdx > group.labelIdx {
2452
- group.label = span.label
2453
- group.start = span.start
2454
- group.labelIdx = span.labelIdx
2455
- }
2456
- forwardStarts[span.start] = group
3231
+ hasGoto := stmtListHasGoto(stmts)
3232
+ var gotoSpans map[string]int
3233
+ var gotoLabels map[string]bool
3234
+ var forwardStarts map[int]forwardGotoLabelSpan
3235
+ if hasGoto {
3236
+ gotoSpans = backwardGotoLabelSpans(stmts)
3237
+ gotoLabels = make(map[string]bool, len(gotoSpans))
3238
+ for label := range gotoSpans {
3239
+ gotoLabels[label] = true
3240
+ }
3241
+ forwardSpans := forwardGotoLabelSpans(stmts, gotoSpans)
3242
+ forwardStarts = make(map[int]forwardGotoLabelSpan, len(forwardSpans))
3243
+ for label, span := range forwardSpans {
3244
+ span.label = label
3245
+ group := forwardStarts[span.start]
3246
+ if group.forwardLabels == nil {
3247
+ group.forwardLabels = make(map[string]bool)
3248
+ }
3249
+ group.forwardLabels[label] = true
3250
+ if group.label == "" || span.labelIdx > group.labelIdx {
3251
+ group.label = span.label
3252
+ group.start = span.start
3253
+ group.labelIdx = span.labelIdx
3254
+ }
3255
+ forwardStarts[span.start] = group
3256
+ }
2457
3257
  }
2458
3258
  for idx := 0; idx < len(stmts); idx++ {
2459
3259
  stmt := stmts[idx]
2460
3260
  startLine := sourceLine(ctx, stmt.Pos())
2461
3261
  leading := leadingStmtLines(ctx, prevEndLine, startLine)
2462
- if cluster, ok := gotoStateClusterAt(stmts, idx); ok {
2463
- clusterLowered, clusterDiagnostics := o.lowerGotoStateCluster(ctx, stmts, cluster, leading)
2464
- diagnostics = append(diagnostics, clusterDiagnostics...)
2465
- lowered = append(lowered, clusterLowered...)
2466
- if endLine := sourceLine(ctx, stmts[cluster.endIdx].End()); endLine != 0 {
2467
- prevEndLine = endLine
2468
- }
2469
- idx = cluster.endIdx
2470
- continue
2471
- }
2472
- if span, ok := leadingGotoBackwardLoopSpan(stmts, idx, gotoSpans); ok {
2473
- loop, loopDiagnostics := o.lowerBackwardGotoLoop(
2474
- ctx,
2475
- gotoLabels,
2476
- span.label,
2477
- span.labelIdx,
2478
- span.endIdx,
2479
- span.forwardLabel,
2480
- stmts,
2481
- leading,
2482
- )
2483
- diagnostics = append(diagnostics, loopDiagnostics...)
2484
- lowered = append(lowered, loop...)
2485
- if endLine := sourceLine(ctx, stmts[span.endIdx].End()); endLine != 0 {
2486
- prevEndLine = endLine
2487
- }
2488
- idx = span.endIdx
2489
- continue
2490
- }
2491
- if span, ok := forwardStarts[idx]; ok {
2492
- bodyStmts := stmts[idx:span.labelIdx]
2493
- body, bodyDiagnostics := o.lowerStmtListAfter(
2494
- ctx.withForwardGotos(span.forwardLabels),
2495
- bodyStmts,
2496
- prevEndLine,
2497
- )
2498
- diagnostics = append(diagnostics, bodyDiagnostics...)
2499
- block := loweredStmt{hasBlock: true, text: span.label + ":", children: body}
2500
- if len(leading) != 0 {
2501
- block.leading = append(leading, block.leading...)
2502
- }
2503
- lowered = append(lowered, block)
2504
- if labeled, ok := stmts[span.labelIdx].(*ast.LabeledStmt); ok {
2505
- labelLowered, labelDiagnostics := o.lowerStmt(ctx, labeled.Stmt)
2506
- diagnostics = append(diagnostics, labelDiagnostics...)
2507
- lowered = append(lowered, labelLowered...)
2508
- if endLine := sourceLine(ctx, labeled.End()); endLine != 0 {
3262
+ if hasGoto {
3263
+ if cluster, ok := gotoStateClusterAt(stmts, idx); ok {
3264
+ clusterLowered, clusterDiagnostics := o.lowerGotoStateCluster(ctx, stmts, cluster, leading)
3265
+ diagnostics = append(diagnostics, clusterDiagnostics...)
3266
+ lowered = append(lowered, clusterLowered...)
3267
+ if endLine := sourceLine(ctx, stmts[cluster.endIdx].End()); endLine != 0 {
2509
3268
  prevEndLine = endLine
2510
3269
  }
3270
+ idx = cluster.endIdx
3271
+ continue
2511
3272
  }
2512
- idx = span.labelIdx
2513
- continue
2514
- }
2515
- if labeled, ok := stmt.(*ast.LabeledStmt); ok {
2516
- label := safeIdentifier(labeled.Label.Name)
2517
- if endIdx, ok := gotoSpans[label]; ok {
3273
+ if span, ok := leadingGotoBackwardLoopSpan(stmts, idx, gotoSpans); ok {
2518
3274
  loop, loopDiagnostics := o.lowerBackwardGotoLoop(
2519
3275
  ctx,
2520
3276
  gotoLabels,
2521
- label,
2522
- idx,
2523
- endIdx,
2524
- "",
3277
+ span.label,
3278
+ span.labelIdx,
3279
+ span.endIdx,
3280
+ span.forwardLabel,
2525
3281
  stmts,
2526
3282
  leading,
2527
3283
  )
2528
3284
  diagnostics = append(diagnostics, loopDiagnostics...)
2529
3285
  lowered = append(lowered, loop...)
2530
- if endLine := sourceLine(ctx, stmts[endIdx].End()); endLine != 0 {
3286
+ if endLine := sourceLine(ctx, stmts[span.endIdx].End()); endLine != 0 {
2531
3287
  prevEndLine = endLine
2532
3288
  }
2533
- idx = endIdx
3289
+ idx = span.endIdx
3290
+ continue
3291
+ }
3292
+ if span, ok := forwardStarts[idx]; ok {
3293
+ bodyStmts := stmts[idx:span.labelIdx]
3294
+ body, bodyDiagnostics := o.lowerStmtListAfter(
3295
+ ctx.withForwardGotos(span.forwardLabels),
3296
+ bodyStmts,
3297
+ prevEndLine,
3298
+ )
3299
+ diagnostics = append(diagnostics, bodyDiagnostics...)
3300
+ block := loweredStmt{hasBlock: true, text: span.label + ":", children: body}
3301
+ if len(leading) != 0 {
3302
+ block.leading = append(leading, block.leading...)
3303
+ }
3304
+ lowered = append(lowered, block)
3305
+ if labeled, ok := stmts[span.labelIdx].(*ast.LabeledStmt); ok {
3306
+ labelLowered, labelDiagnostics := o.lowerStmt(ctx, labeled.Stmt)
3307
+ diagnostics = append(diagnostics, labelDiagnostics...)
3308
+ lowered = append(lowered, labelLowered...)
3309
+ if endLine := sourceLine(ctx, labeled.End()); endLine != 0 {
3310
+ prevEndLine = endLine
3311
+ }
3312
+ }
3313
+ idx = span.labelIdx
2534
3314
  continue
2535
3315
  }
3316
+ if labeled, ok := stmt.(*ast.LabeledStmt); ok {
3317
+ label := safeIdentifier(labeled.Label.Name)
3318
+ if endIdx, ok := gotoSpans[label]; ok {
3319
+ loop, loopDiagnostics := o.lowerBackwardGotoLoop(
3320
+ ctx,
3321
+ gotoLabels,
3322
+ label,
3323
+ idx,
3324
+ endIdx,
3325
+ "",
3326
+ stmts,
3327
+ leading,
3328
+ )
3329
+ diagnostics = append(diagnostics, loopDiagnostics...)
3330
+ lowered = append(lowered, loop...)
3331
+ if endLine := sourceLine(ctx, stmts[endIdx].End()); endLine != 0 {
3332
+ prevEndLine = endLine
3333
+ }
3334
+ idx = endIdx
3335
+ continue
3336
+ }
3337
+ }
2536
3338
  }
2537
3339
  if stmtCtx, nextCtx, ok := o.lowerDeclStatementContext(ctx, stmt); ok {
2538
3340
  stmtLowered, stmtDiagnostics := o.lowerStmt(stmtCtx, stmt)
@@ -2604,7 +3406,7 @@ func (o *LoweringOwner) lowerDeclStatementContext(
2604
3406
  if def == nil || aliases[def] != "" {
2605
3407
  continue
2606
3408
  }
2607
- if shortDeclDefShadowsOuterName(name.Name, def) {
3409
+ if shortDeclDefShadowsOuterName(ctx, name.Name, def) || valueSpecUsesOuterName(ctx, valueSpec, name.Name, def) {
2608
3410
  aliases[def] = ctx.tempName("Shadow")
2609
3411
  }
2610
3412
  }
@@ -2852,9 +3654,30 @@ type leadingGotoBackwardLoop struct {
2852
3654
  }
2853
3655
 
2854
3656
  func stmtListNeedsLoopBranchLabel(stmts []ast.Stmt) bool {
3657
+ if !stmtListHasGoto(stmts) {
3658
+ return false
3659
+ }
2855
3660
  return len(backwardGotoLabelSpans(stmts)) != 0
2856
3661
  }
2857
3662
 
3663
+ func stmtListHasGoto(stmts []ast.Stmt) bool {
3664
+ for _, stmt := range stmts {
3665
+ hasGoto := false
3666
+ ast.Inspect(stmt, func(node ast.Node) bool {
3667
+ branch, ok := node.(*ast.BranchStmt)
3668
+ if ok && branch.Tok == token.GOTO && branch.Label != nil {
3669
+ hasGoto = true
3670
+ return false
3671
+ }
3672
+ return !hasGoto
3673
+ })
3674
+ if hasGoto {
3675
+ return true
3676
+ }
3677
+ }
3678
+ return false
3679
+ }
3680
+
2858
3681
  func backwardGotoLabelSpans(stmts []ast.Stmt) map[string]int {
2859
3682
  seenLabels := make(map[string]bool)
2860
3683
  spans := make(map[string]int)
@@ -3134,15 +3957,11 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3134
3957
  if starTarget && stmt.Tok != token.DEFINE {
3135
3958
  pointer, pointerDiagnostics := o.lowerPointerStorageExpr(ctx, star.X)
3136
3959
  diagnostics = append(diagnostics, pointerDiagnostics...)
3137
- if stmt.Tok == token.AND_NOT_ASSIGN {
3138
- stmts = append(stmts, loweredStmt{text: pointer + " = " + pointer + " & ~(" + right + ")"})
3139
- continue
3140
- }
3141
3960
  if value, ok := integerQuotientAssignExpr(targetType, pointer, right, stmt.Tok); ok {
3142
3961
  stmts = append(stmts, loweredStmt{text: value})
3143
3962
  continue
3144
3963
  }
3145
- stmts = append(stmts, loweredStmt{text: pointer + " " + stmt.Tok.String() + " " + right})
3964
+ stmts = append(stmts, loweredStmt{text: pointer + " = " + lowerCompoundAssignValue(o.runtimeOwner, targetType, pointer, right, stmt.Tok)})
3146
3965
  continue
3147
3966
  }
3148
3967
  if isShortDecl {
@@ -3152,10 +3971,6 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3152
3971
  stmts = append(stmts, loweredStmt{text: "let " + left + o.shortDeclTypeAnnotation(ctx, lhs, stmt.Rhs[idx]) + " = " + right})
3153
3972
  continue
3154
3973
  }
3155
- if stmt.Tok == token.AND_NOT_ASSIGN {
3156
- stmts = append(stmts, loweredStmt{text: left + " = " + left + " & ~(" + right + ")"})
3157
- continue
3158
- }
3159
3974
  if helper, ok := wideIntegerAssignHelper(targetType, stmt.Tok); ok {
3160
3975
  stmts = append(stmts, loweredStmt{text: left + " = " + o.runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")"})
3161
3976
  continue
@@ -3168,6 +3983,10 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3168
3983
  if stmt.Tok == token.DEFINE {
3169
3984
  op = "="
3170
3985
  }
3986
+ if stmt.Tok != token.ASSIGN && stmt.Tok != token.DEFINE {
3987
+ stmts = append(stmts, loweredStmt{text: left + " = " + lowerCompoundAssignValue(o.runtimeOwner, targetType, left, right, stmt.Tok)})
3988
+ continue
3989
+ }
3171
3990
  stmts = append(stmts, loweredStmt{text: left + " " + op + " " + right})
3172
3991
  }
3173
3992
  return stmts, diagnostics
@@ -3210,6 +4029,7 @@ func lowerCompoundAssignValue(
3210
4029
  if value, ok := integerQuotientAssignValueExpr(targetType, left, right, tok); ok {
3211
4030
  return value
3212
4031
  }
4032
+ right = "(" + right + ")"
3213
4033
  switch tok {
3214
4034
  case token.ADD_ASSIGN:
3215
4035
  return left + " + " + right
@@ -3230,6 +4050,9 @@ func lowerCompoundAssignValue(
3230
4050
  case token.SHL_ASSIGN:
3231
4051
  return left + " << " + right
3232
4052
  case token.SHR_ASSIGN:
4053
+ if bits, ok := unsignedIntegerBits(targetType); ok && bits <= 32 {
4054
+ return "(" + left + " >>> " + right + ") >>> 0"
4055
+ }
3233
4056
  return left + " >> " + right
3234
4057
  case token.AND_NOT_ASSIGN:
3235
4058
  return left + " & ~(" + right + ")"
@@ -3266,30 +4089,31 @@ func integerQuotientAssignValueExpr(targetType types.Type, left string, right st
3266
4089
  }
3267
4090
 
3268
4091
  func wideIntegerAssignHelper(targetType types.Type, tok token.Token) (RuntimeHelper, bool) {
3269
- if !isFixedWideIntegerType(targetType) {
4092
+ if !isRuntimeWideIntegerType(targetType) {
3270
4093
  return "", false
3271
4094
  }
4095
+ signed := isFixedSignedWideIntegerType(targetType)
3272
4096
  switch tok {
3273
4097
  case token.SHL_ASSIGN:
3274
- return RuntimeHelperUint64Shl, true
4098
+ return wideIntegerHelper(signed, RuntimeHelperUint64Shl, RuntimeHelperInt64Shl), true
3275
4099
  case token.SHR_ASSIGN:
3276
- return RuntimeHelperUint64Shr, true
4100
+ return wideIntegerHelper(signed, RuntimeHelperUint64Shr, RuntimeHelperInt64Shr), true
3277
4101
  case token.MUL_ASSIGN:
3278
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Mul, RuntimeHelperInt64Mul), true
4102
+ return wideIntegerHelper(signed, RuntimeHelperUint64Mul, RuntimeHelperInt64Mul), true
3279
4103
  case token.QUO_ASSIGN:
3280
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Div, RuntimeHelperInt64Div), true
4104
+ return wideIntegerHelper(signed, RuntimeHelperUint64Div, RuntimeHelperInt64Div), true
3281
4105
  case token.REM_ASSIGN:
3282
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Mod, RuntimeHelperInt64Mod), true
4106
+ return wideIntegerHelper(signed, RuntimeHelperUint64Mod, RuntimeHelperInt64Mod), true
3283
4107
  case token.ADD_ASSIGN:
3284
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Add, RuntimeHelperInt64Add), true
4108
+ return wideIntegerHelper(signed, RuntimeHelperUint64Add, RuntimeHelperInt64Add), true
3285
4109
  case token.SUB_ASSIGN:
3286
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Sub, RuntimeHelperInt64Sub), true
4110
+ return wideIntegerHelper(signed, RuntimeHelperUint64Sub, RuntimeHelperInt64Sub), true
3287
4111
  case token.AND_ASSIGN:
3288
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64And, RuntimeHelperInt64And), true
4112
+ return wideIntegerHelper(signed, RuntimeHelperUint64And, RuntimeHelperInt64And), true
3289
4113
  case token.OR_ASSIGN:
3290
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Or, RuntimeHelperInt64Or), true
4114
+ return wideIntegerHelper(signed, RuntimeHelperUint64Or, RuntimeHelperInt64Or), true
3291
4115
  case token.XOR_ASSIGN:
3292
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Xor, RuntimeHelperInt64Xor), true
4116
+ return wideIntegerHelper(signed, RuntimeHelperUint64Xor, RuntimeHelperInt64Xor), true
3293
4117
  default:
3294
4118
  return "", false
3295
4119
  }
@@ -3366,12 +4190,20 @@ func (o *LoweringOwner) shortDeclTypeAnnotation(ctx lowerFileContext, lhs ast.Ex
3366
4190
  }
3367
4191
  return ": " + typ
3368
4192
  }
4193
+ if rhs != nil && isIdentLikeExpr(rhs) && isInterfaceType(obj.Type()) {
4194
+ return ": " + o.tsVariableTypeFor(ctx, obj.Type(), ctx.model.needsVarRef[obj])
4195
+ }
3369
4196
  if !shortDeclNeedsTypeAnnotation(obj.Type()) {
3370
4197
  return ""
3371
4198
  }
3372
4199
  return ": " + o.tsVariableTypeFor(ctx, obj.Type(), ctx.model.needsVarRef[obj])
3373
4200
  }
3374
4201
 
4202
+ func isIdentLikeExpr(expr ast.Expr) bool {
4203
+ _, ok := ast.Unparen(expr).(*ast.Ident)
4204
+ return ok
4205
+ }
4206
+
3375
4207
  func shortDeclNeedsTypeAnnotation(typ types.Type) bool {
3376
4208
  switch typed := types.Unalias(typ).Underlying().(type) {
3377
4209
  case *types.Pointer:
@@ -3401,6 +4233,15 @@ func (o *LoweringOwner) lowerTupleTargetAssignmentStmt(
3401
4233
  declare bool,
3402
4234
  ) (loweredStmt, []Diagnostic) {
3403
4235
  if !declare {
4236
+ if index, ok := unwrapParenExpr(lhs).(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) {
4237
+ targetType := assignmentTargetType(ctx, lhs)
4238
+ value = o.lowerValueForTarget(ctx, lhs, targetType, value)
4239
+ stmts, diagnostics := o.lowerMapIndexUpdateStmts(ctx, index, token.ASSIGN, value, targetType)
4240
+ if len(stmts) != 0 {
4241
+ return stmts[0], diagnostics
4242
+ }
4243
+ return loweredStmt{}, diagnostics
4244
+ }
3404
4245
  if stmt, diagnostics, ok := o.lowerStarTargetAssignmentStmt(ctx, lhs, value); ok {
3405
4246
  return stmt, diagnostics
3406
4247
  }
@@ -3555,7 +4396,7 @@ func (o *LoweringOwner) lowerShortDeclNewShadowAliases(
3555
4396
  if entry.def == nil || aliases[entry.def] != "" {
3556
4397
  continue
3557
4398
  }
3558
- if shortDeclDefShadowsOuterName(entry.name, entry.def) {
4399
+ if shortDeclDefShadowsOuterName(ctx, entry.name, entry.def) {
3559
4400
  aliases[entry.def] = ctx.tempName("Shadow")
3560
4401
  }
3561
4402
  }
@@ -3584,12 +4425,24 @@ func shortDeclShadowNonValueIdents(ctx lowerFileContext, expr ast.Expr) map[*ast
3584
4425
  return idents
3585
4426
  }
3586
4427
 
3587
- func shortDeclDefShadowsOuterName(name string, def types.Object) bool {
4428
+ func shortDeclDefShadowsOuterName(ctx lowerFileContext, name string, def types.Object) bool {
3588
4429
  for scope := def.Parent(); scope != nil; scope = scope.Parent() {
3589
4430
  if scope == def.Parent() {
3590
4431
  continue
3591
4432
  }
3592
4433
  obj := scope.Lookup(name)
4434
+ if scope.Parent() == types.Universe {
4435
+ if obj == nil {
4436
+ return false
4437
+ }
4438
+ if _, isTypeName := obj.(*types.TypeName); isTypeName {
4439
+ return true
4440
+ }
4441
+ if _, isFunc := obj.(*types.Func); isFunc {
4442
+ return sameSourceFile(ctx, obj.Pos(), def.Pos()) && obj.Pos() < def.Pos()
4443
+ }
4444
+ return false
4445
+ }
3593
4446
  if obj != nil && obj.Pos().IsValid() && obj.Pos() < def.Pos() {
3594
4447
  return true
3595
4448
  }
@@ -3597,6 +4450,40 @@ func shortDeclDefShadowsOuterName(name string, def types.Object) bool {
3597
4450
  return false
3598
4451
  }
3599
4452
 
4453
+ func sameSourceFile(ctx lowerFileContext, left token.Pos, right token.Pos) bool {
4454
+ if !left.IsValid() || !right.IsValid() || ctx.semPkg == nil || ctx.semPkg.source == nil {
4455
+ return false
4456
+ }
4457
+ leftPos := sourcePos(ctx.semPkg.source, left)
4458
+ rightPos := sourcePos(ctx.semPkg.source, right)
4459
+ return leftPos.file != "" && leftPos.file == rightPos.file
4460
+ }
4461
+
4462
+ func valueSpecUsesOuterName(ctx lowerFileContext, spec *ast.ValueSpec, name string, def types.Object) bool {
4463
+ if spec == nil || name == "" || def == nil {
4464
+ return false
4465
+ }
4466
+ usesOuter := false
4467
+ for _, value := range spec.Values {
4468
+ ast.Inspect(value, func(node ast.Node) bool {
4469
+ ident, ok := node.(*ast.Ident)
4470
+ if !ok || ident.Name != name {
4471
+ return true
4472
+ }
4473
+ obj := ctx.semPkg.source.TypesInfo.Uses[ident]
4474
+ if obj != nil && obj != def {
4475
+ usesOuter = true
4476
+ return false
4477
+ }
4478
+ return true
4479
+ })
4480
+ if usesOuter {
4481
+ return true
4482
+ }
4483
+ }
4484
+ return false
4485
+ }
4486
+
3600
4487
  func (o *LoweringOwner) mapIndexDefaultUsesShortDeclName(
3601
4488
  ctx lowerFileContext,
3602
4489
  rhs ast.Expr,
@@ -4656,7 +5543,7 @@ func (o *LoweringOwner) lowerRangeFuncStmt(
4656
5543
  diagnostics = append(diagnostics, assignmentDiagnostics...)
4657
5544
  body = append(assignments, body...)
4658
5545
  }
4659
- async := ctx.asyncFunction
5546
+ async := ctx.asyncFunction || stmtsContainAwait(body) || o.rangeFunctionValueNeedsAwait(ctx, stmt.X)
4660
5547
 
4661
5548
  return loweredStmt{rangeFunc: &loweredRangeFunc{
4662
5549
  value: rangeValue,
@@ -5285,6 +6172,19 @@ func (o *LoweringOwner) lowerComplexEqualityExpr(ctx lowerFileContext, expr *ast
5285
6172
  return value, true
5286
6173
  }
5287
6174
 
6175
+ func (o *LoweringOwner) lowerStructEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
6176
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
6177
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
6178
+ if !isStructComparableType(leftType) || !isStructComparableType(rightType) {
6179
+ return "", false
6180
+ }
6181
+ value := o.runtimeOwner.QualifiedHelper(RuntimeHelperComparableEqual) + "(" + left + ", " + right + ")"
6182
+ if expr.Op == token.NEQ {
6183
+ value = "!" + value
6184
+ }
6185
+ return value, true
6186
+ }
6187
+
5288
6188
  func (o *LoweringOwner) lowerStringEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
5289
6189
  leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5290
6190
  rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
@@ -5413,6 +6313,9 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
5413
6313
  if value, ok := o.lowerComplexEqualityExpr(ctx, typed, left, right); ok {
5414
6314
  return value, append(leftDiagnostics, rightDiagnostics...)
5415
6315
  }
6316
+ if value, ok := o.lowerStructEqualityExpr(ctx, typed, left, right); ok {
6317
+ return value, append(leftDiagnostics, rightDiagnostics...)
6318
+ }
5416
6319
  if value, ok := o.lowerStringEqualityExpr(ctx, typed, left, right); ok {
5417
6320
  return value, append(leftDiagnostics, rightDiagnostics...)
5418
6321
  }
@@ -5456,6 +6359,10 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
5456
6359
  return lowerPrefixUnaryExpr(typed.Op, value), diagnostics
5457
6360
  }
5458
6361
  if typed.Op == token.XOR {
6362
+ if bits, ok := unsignedIntegerBits(ctx.semPkg.source.TypesInfo.TypeOf(typed)); ok && bits <= 32 {
6363
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
6364
+ "(~" + value + ", " + strconv.Itoa(bits) + ")", diagnostics
6365
+ }
5459
6366
  return "~" + value, diagnostics
5460
6367
  }
5461
6368
  return value, append(diagnostics, loweringUnsupported("expression", ctx.semPkg.pkgPath, "unsupported unary operator"))
@@ -5538,7 +6445,7 @@ func isLegacyOctalLiteral(value string) bool {
5538
6445
  func (o *LoweringOwner) lowerFuncLit(ctx lowerFileContext, lit *ast.FuncLit) (string, bool, []Diagnostic) {
5539
6446
  signature, _ := ctx.semPkg.source.TypesInfo.TypeOf(lit).(*types.Signature)
5540
6447
  deferState := &loweredDeferState{}
5541
- bodyCtx := ctx.withSignature(signature).withDeferState(deferState).withoutRangeBranch()
6448
+ bodyCtx := ctx.withSignature(signature).withAsyncFunction(false).withDeferState(deferState).withoutRangeBranch()
5542
6449
  asyncCompatibleParams := funcLiteralNeedsAsyncFunctionParamCalls(signature)
5543
6450
  if asyncCompatibleParams || funcLiteralUsesFunctionIdentifierCall(ctx, lit) {
5544
6451
  bodyCtx = bodyCtx.withAsyncFunction(true)
@@ -5659,7 +6566,7 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
5659
6566
  }
5660
6567
  return alias
5661
6568
  }
5662
- if constObj, ok := obj.(*types.Const); ok && ctx.localAliases[obj] != "" {
6569
+ if constObj, ok := obj.(*types.Const); ok && !raw {
5663
6570
  if constValue, ok := lowerConstantValue(constObj.Val()); ok {
5664
6571
  return constValue
5665
6572
  }
@@ -5667,6 +6574,9 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
5667
6574
  if alias := ctx.localAliases[obj]; alias != "" {
5668
6575
  if ctx.lazyPackageVars[obj] {
5669
6576
  lazyValue := alias + "." + packageVarGetterName(value) + "()"
6577
+ if (ctx.asyncFunction || ctx.topLevel) && o.packageVarHasAsyncLazyInit(ctx, obj) {
6578
+ lazyValue = "(await " + alias + "." + packageVarInitName(value) + "(), " + lazyValue + ")"
6579
+ }
5670
6580
  if raw {
5671
6581
  return lazyValue
5672
6582
  }
@@ -5682,6 +6592,9 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
5682
6592
  }
5683
6593
  if ctx.lazyPackageVars[obj] {
5684
6594
  lazyValue := packageVarGetterName(value) + "()"
6595
+ if (ctx.asyncFunction || ctx.topLevel) && o.packageVarHasAsyncLazyInit(ctx, obj) {
6596
+ lazyValue = "(await " + packageVarInitName(value) + "(), " + lazyValue + ")"
6597
+ }
5685
6598
  return o.lowerPackageVarReadValue(ctx, obj, lazyValue)
5686
6599
  }
5687
6600
  if obj != nil && ctx.model.needsVarRef[obj] {
@@ -6339,6 +7252,8 @@ func (o *LoweringOwner) lowerConversionExpr(
6339
7252
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperRunesToString) + "(" + value + ")", diagnostics
6340
7253
  case isByteSliceType(sourceType):
6341
7254
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperBytesToString) + "(" + value + ")", diagnostics
7255
+ case overrideNamedStringType(ctx, o, sourceType):
7256
+ return "String(" + value + ")", diagnostics
6342
7257
  case isStringType(sourceType):
6343
7258
  return value, diagnostics
6344
7259
  case isNumericType(sourceType):
@@ -6397,7 +7312,7 @@ func (o *LoweringOwner) lowerConversionExpr(
6397
7312
  return renderNamedStructConversion(conversion), diagnostics
6398
7313
  }
6399
7314
  if isNumericType(targetType) {
6400
- if constantValue, ok := lowerRealNumericConstantExpr(ctx, expr.Args[0]); ok {
7315
+ if constantValue, ok := o.lowerNumericConstantExprForTarget(ctx, expr.Args[0], targetType); ok {
6401
7316
  return constantValue, diagnostics
6402
7317
  }
6403
7318
  }
@@ -6429,8 +7344,8 @@ func (o *LoweringOwner) lowerConversionExpr(
6429
7344
  }
6430
7345
 
6431
7346
  func (o *LoweringOwner) lowerWideIntegerBinaryExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
6432
- resultWide := isFixedWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr))
6433
- leftWide := isFixedWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
7347
+ resultWide := isRuntimeWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr))
7348
+ leftWide := isRuntimeWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
6434
7349
  if !resultWide && !leftWide {
6435
7350
  return "", false
6436
7351
  }
@@ -6696,6 +7611,22 @@ func (o *LoweringOwner) lowerPointerReceiverMethodCall(
6696
7611
  return "", nil, false
6697
7612
  }
6698
7613
  receiverExpr, diagnostics := o.lowerExpr(ctx, selector.X)
7614
+ if o.receiverUsesOverridePackage(signature.Recv().Type()) {
7615
+ receiverExpr = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
7616
+ "<" + o.tsTypeFor(ctx, signature.Recv().Type().(*types.Pointer).Elem()) + ">(" + receiverExpr + ")"
7617
+ }
7618
+ if receiverExpr == o.namedTypeExpr(ctx, receiver) {
7619
+ call := o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
7620
+ "<" + o.namedTypeExpr(ctx, receiver) + ">(" + receiverExpr + ")." +
7621
+ methodMemberName(selector.Sel.Name) + "(" + strings.Join(args, ", ") + ")"
7622
+ return call, diagnostics, true
7623
+ }
7624
+ if crossPackageUnexportedNamedType(ctx, receiver) {
7625
+ call := o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
7626
+ "<any>(" + receiverExpr + ")." + methodMemberName(selector.Sel.Name) +
7627
+ "(" + strings.Join(args, ", ") + ")"
7628
+ return call, diagnostics, true
7629
+ }
6699
7630
  callArgs := append([]string{receiverExpr}, args...)
6700
7631
  call := o.namedTypeExpr(ctx, receiver) + ".prototype." + selector.Sel.Name + ".call(" + strings.Join(callArgs, ", ") + ")"
6701
7632
  return call, diagnostics, true
@@ -6813,6 +7744,14 @@ func (o *LoweringOwner) lowerSelectorExpr(ctx lowerFileContext, expr *ast.Select
6813
7744
  if alias := importAliasForPkgName(ctx, pkgName); alias != "" {
6814
7745
  value := alias + "." + expr.Sel.Name
6815
7746
  obj, _ := ctx.semPkg.source.TypesInfo.Uses[expr.Sel].(*types.Var)
7747
+ if o.packageVarIsLazy(ctx, obj) ||
7748
+ o.packageVarNameIsLazy(ctx, pkgName.Imported().Path(), expr.Sel.Name) {
7749
+ value = alias + "." + packageVarGetterName(expr.Sel.Name) + "()"
7750
+ if (ctx.asyncFunction || ctx.topLevel) &&
7751
+ o.packageVarNameHasAsyncLazyInit(ctx, pkgName.Imported().Path(), expr.Sel.Name) {
7752
+ value = "(await " + alias + "." + packageVarInitName(expr.Sel.Name) + "(), " + value + ")"
7753
+ }
7754
+ }
6816
7755
  if obj != nil && packageVarReadNeedsPointerValue(obj.Type()) {
6817
7756
  value = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
6818
7757
  "<" + o.tsNonNilTypeFor(ctx, obj.Type()) + ">(" + value + ")"
@@ -6887,10 +7826,13 @@ func (o *LoweringOwner) packageVarSetterForAssignment(ctx lowerFileContext, expr
6887
7826
  return "", false
6888
7827
  }
6889
7828
  alias := ctx.localAliases[obj]
6890
- if alias == "" {
6891
- return "", false
7829
+ if alias != "" {
7830
+ return alias + "." + packageVarSetterName(ident.Name), true
6892
7831
  }
6893
- return alias + "." + packageVarSetterName(ident.Name), true
7832
+ if ctx.lazyPackageVars[obj] {
7833
+ return packageVarSetterName(ident.Name), true
7834
+ }
7835
+ return "", false
6894
7836
  }
6895
7837
  selector, ok := unwrapParenExpr(expr).(*ast.SelectorExpr)
6896
7838
  if !ok {
@@ -7848,12 +8790,40 @@ func (o *LoweringOwner) lowerStructCompositeLit(
7848
8790
  func compositeLiteralFieldNeedsPreEval(ctx lowerFileContext, expr ast.Expr) bool {
7849
8791
  switch typed := unwrapParenExpr(expr).(type) {
7850
8792
  case *ast.CallExpr:
8793
+ for _, arg := range typed.Args {
8794
+ if compositeLiteralFieldNeedsPreEval(ctx, arg) {
8795
+ return true
8796
+ }
8797
+ }
7851
8798
  if ident, ok := typed.Fun.(*ast.Ident); ok && isBuiltinCallTarget(ctx, ident) {
7852
8799
  return false
7853
8800
  }
7854
8801
  return typeFromExpr(ctx, typed.Fun) == nil
7855
8802
  case *ast.UnaryExpr:
7856
- return typed.Op == token.ARROW
8803
+ return typed.Op == token.ARROW || compositeLiteralFieldNeedsPreEval(ctx, typed.X)
8804
+ case *ast.BinaryExpr:
8805
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X) ||
8806
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Y)
8807
+ case *ast.IndexExpr:
8808
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X) ||
8809
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Index)
8810
+ case *ast.IndexListExpr:
8811
+ if compositeLiteralFieldNeedsPreEval(ctx, typed.X) {
8812
+ return true
8813
+ }
8814
+ for _, index := range typed.Indices {
8815
+ if compositeLiteralFieldNeedsPreEval(ctx, index) {
8816
+ return true
8817
+ }
8818
+ }
8819
+ return false
8820
+ case *ast.SliceExpr:
8821
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X) ||
8822
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Low) ||
8823
+ compositeLiteralFieldNeedsPreEval(ctx, typed.High) ||
8824
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Max)
8825
+ case *ast.StarExpr:
8826
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X)
7857
8827
  default:
7858
8828
  return false
7859
8829
  }
@@ -7918,6 +8888,9 @@ func (o *LoweringOwner) lowerArrayCompositeLit(
7918
8888
  lit *ast.CompositeLit,
7919
8889
  array *types.Array,
7920
8890
  ) (string, []Diagnostic) {
8891
+ if len(lit.Elts) == 0 && isByteType(array.Elem()) {
8892
+ return "new Uint8Array(" + strconv.FormatInt(array.Len(), 10) + ")", nil
8893
+ }
7921
8894
  values := make([]string, int(array.Len()))
7922
8895
  for idx := range values {
7923
8896
  values[idx] = o.lowerZeroValueExprFor(ctx, array.Elem())
@@ -8071,7 +9044,7 @@ func (o *LoweringOwner) lowerValueForTarget(
8071
9044
  }
8072
9045
  }
8073
9046
  if isNumericType(targetType) {
8074
- if constantValue, ok := lowerRealNumericConstantExpr(ctx, expr); ok {
9047
+ if constantValue, ok := o.lowerNumericConstantExprForTarget(ctx, expr, targetType); ok {
8075
9048
  return constantValue
8076
9049
  }
8077
9050
  }
@@ -8100,6 +9073,28 @@ func lowerRealNumericConstantExpr(ctx lowerFileContext, expr ast.Expr) (string,
8100
9073
  }
8101
9074
  }
8102
9075
 
9076
+ func (o *LoweringOwner) lowerNumericConstantExprForTarget(ctx lowerFileContext, expr ast.Expr, targetType types.Type) (string, bool) {
9077
+ if ctx.semPkg == nil || ctx.semPkg.source == nil {
9078
+ return "", false
9079
+ }
9080
+ tv, ok := ctx.semPkg.source.TypesInfo.Types[expr]
9081
+ if ok && tv.Value != nil {
9082
+ if bits, ok := unsignedIntegerBits(targetType); ok && bits >= 64 {
9083
+ if value, ok := lowerWideIntegerConstantValue(tv.Value); ok {
9084
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) + "(" +
9085
+ strconv.Quote(value) + ", 64)", true
9086
+ }
9087
+ }
9088
+ if bits, ok := signedIntegerBits(targetType); ok && bits >= 64 {
9089
+ if value, ok := lowerWideIntegerConstantValue(tv.Value); ok {
9090
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperInt) + "(" +
9091
+ strconv.Quote(value) + ", 64)", true
9092
+ }
9093
+ }
9094
+ }
9095
+ return lowerRealNumericConstantExpr(ctx, expr)
9096
+ }
9097
+
8103
9098
  func isRealNumericConstantExpr(ctx lowerFileContext, expr ast.Expr) bool {
8104
9099
  if ctx.semPkg != nil && ctx.semPkg.source != nil {
8105
9100
  if tv, ok := ctx.semPkg.source.TypesInfo.Types[expr]; ok && tv.Value != nil {
@@ -8145,6 +9140,9 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
8145
9140
  return wrapper
8146
9141
  }
8147
9142
  }
9143
+ if wrapper := o.lowerNumericInterfaceWrapper(ctx, targetType, sourceType, value); wrapper != "" {
9144
+ return wrapper
9145
+ }
8148
9146
  if isInterfaceType(targetType) && isStructValueType(sourceType) {
8149
9147
  if cloneStructValue {
8150
9148
  value = o.lowerStructClone(value)
@@ -8193,6 +9191,25 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
8193
9191
  return value
8194
9192
  }
8195
9193
 
9194
+ func (o *LoweringOwner) lowerNumericInterfaceWrapper(
9195
+ ctx lowerFileContext,
9196
+ targetType types.Type,
9197
+ sourceType types.Type,
9198
+ value string,
9199
+ ) string {
9200
+ if targetType == nil || sourceType == nil || !isInterfaceType(targetType) || isInterfaceType(sourceType) {
9201
+ return ""
9202
+ }
9203
+ basic, ok := types.Unalias(sourceType).(*types.Basic)
9204
+ if !ok || basic.Info()&types.IsNumeric == 0 || basic.Info()&types.IsUntyped != 0 {
9205
+ return ""
9206
+ }
9207
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
9208
+ "<" + o.tsTypeFor(ctx, targetType) + ">(" + value + ", " +
9209
+ strconv.Quote(goRuntimeTypeString(sourceType)) + ", {}, " +
9210
+ o.runtimeTypeInfoExpr(sourceType) + ")"
9211
+ }
9212
+
8196
9213
  func isBasicFixedWideIntegerType(typ types.Type) bool {
8197
9214
  basic, ok := types.Unalias(typ).(*types.Basic)
8198
9215
  if !ok {
@@ -8232,7 +9249,8 @@ func (o *LoweringOwner) lowerNamedValueInterfaceWrapper(
8232
9249
  }
8233
9250
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
8234
9251
  "<" + o.tsTypeFor(ctx, targetType) + ">(" + value + ", " +
8235
- strconv.Quote(goRuntimeTypeString(sourceType)) + ", " + methods + ")"
9252
+ strconv.Quote(goRuntimeTypeString(sourceType)) + ", " + methods + ", " +
9253
+ o.runtimeTypeInfoExpr(sourceType) + ")"
8236
9254
  }
8237
9255
 
8238
9256
  func (o *LoweringOwner) lowerPrimitiveErrorWrapper(ctx lowerFileContext, sourceType types.Type, value string) string {
@@ -8254,7 +9272,8 @@ func (o *LoweringOwner) lowerPrimitiveErrorWrapper(ctx lowerFileContext, sourceT
8254
9272
  }
8255
9273
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
8256
9274
  "<$.GoError>(" + value + ", " + strconv.Quote(goRuntimeTypeString(sourceType)) +
8257
- ", {\"Error\": " + o.methodFunctionExpr(ctx, named, fn, "Error") + "})"
9275
+ ", {\"Error\": " + o.methodFunctionExpr(ctx, named, fn, "Error") + "}, " +
9276
+ o.runtimeTypeInfoExpr(sourceType) + ")"
8258
9277
  }
8259
9278
 
8260
9279
  func (o *LoweringOwner) lowerStructClone(value string) string {
@@ -8264,7 +9283,7 @@ func (o *LoweringOwner) lowerStructClone(value string) string {
8264
9283
 
8265
9284
  func (o *LoweringOwner) lowerZeroValueExpr(typ types.Type) string {
8266
9285
  if named := namedStructType(typ); named != nil && isStructValueType(typ) {
8267
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue) + "(new " + named.Obj().Name() + "())"
9286
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue) + "(new " + safeIdentifier(named.Obj().Name()) + "())"
8268
9287
  }
8269
9288
  return zeroValueExpr(typ)
8270
9289
  }
@@ -8311,7 +9330,7 @@ func (o *LoweringOwner) lowerZeroValueExprFor(ctx lowerFileContext, typ types.Ty
8311
9330
 
8312
9331
  func (o *LoweringOwner) lowerDeclarationZeroValueExpr(ctx lowerFileContext, typ types.Type) string {
8313
9332
  if isFunctionType(typ) {
8314
- return "null as " + o.tsTypeFor(ctx, typ)
9333
+ return "null as unknown as " + o.tsFunctionZeroValueTypeFor(ctx, typ)
8315
9334
  }
8316
9335
  typeParam, ok := types.Unalias(typ).(*types.TypeParam)
8317
9336
  if !ok {
@@ -8328,6 +9347,13 @@ func (o *LoweringOwner) lowerDeclarationZeroValueExpr(ctx lowerFileContext, typ
8328
9347
  "(__typeArgs, " + strconv.Quote(typeParam.Obj().Name()) + ", " + zeroValueExpr(typ) + ")"
8329
9348
  }
8330
9349
 
9350
+ func (o *LoweringOwner) tsFunctionZeroValueTypeFor(ctx lowerFileContext, typ types.Type) string {
9351
+ if signature := unnamedSignatureForType(typ); signature != nil {
9352
+ return o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
9353
+ }
9354
+ return o.tsTypeFor(ctx, typ)
9355
+ }
9356
+
8331
9357
  func (o *LoweringOwner) runtimeTypeInfoExpr(typ types.Type) string {
8332
9358
  return o.runtimeTypeInfoExprWithSeen(typ, make(map[types.Type]bool))
8333
9359
  }
@@ -8789,6 +9815,9 @@ func (o *LoweringOwner) tsNonNilTypeFor(ctx lowerFileContext, typ types.Type) st
8789
9815
  }
8790
9816
  if named, ok := types.Unalias(typ).(*types.Named); ok {
8791
9817
  if _, ok := named.Underlying().(*types.Interface); ok {
9818
+ if !ctx.canReferenceNamedType(named) {
9819
+ return "any"
9820
+ }
8792
9821
  return "Exclude<" + o.namedTypeExpr(ctx, named) + ", null>"
8793
9822
  }
8794
9823
  }
@@ -8851,7 +9880,7 @@ func zeroValueExpr(typ types.Type) string {
8851
9880
  return "undefined"
8852
9881
  }
8853
9882
  if named := namedStructType(typ); named != nil && isStructValueType(typ) {
8854
- return "new " + named.Obj().Name() + "()"
9883
+ return "new " + safeIdentifier(named.Obj().Name()) + "()"
8855
9884
  }
8856
9885
  switch typed := types.Unalias(typ).Underlying().(type) {
8857
9886
  case *types.Basic:
@@ -8941,6 +9970,11 @@ func namedFunctionType(typ types.Type) *types.Named {
8941
9970
  return named
8942
9971
  }
8943
9972
 
9973
+ func overrideNamedStringType(ctx lowerFileContext, owner *LoweringOwner, typ types.Type) bool {
9974
+ named, _ := types.Unalias(typ).(*types.Named)
9975
+ return named != nil && isStringType(named) && owner.typeUsesOverride(named)
9976
+ }
9977
+
8944
9978
  func isBuiltinErrorType(typ types.Type) bool {
8945
9979
  if typ == nil {
8946
9980
  return false
@@ -9091,6 +10125,16 @@ func isStructValueType(typ types.Type) bool {
9091
10125
  return namedStructType(typ) != nil
9092
10126
  }
9093
10127
 
10128
+ func isStructComparableType(typ types.Type) bool {
10129
+ if typ == nil {
10130
+ return false
10131
+ }
10132
+ if _, ok := types.Unalias(typ).Underlying().(*types.Struct); !ok {
10133
+ return false
10134
+ }
10135
+ return types.Comparable(typ)
10136
+ }
10137
+
9094
10138
  func isPointerToStructType(typ types.Type) bool {
9095
10139
  pointer, ok := types.Unalias(typ).Underlying().(*types.Pointer)
9096
10140
  if !ok {
@@ -9270,6 +10314,14 @@ func isFixedSignedWideIntegerType(typ types.Type) bool {
9270
10314
  return ok && basic.Kind() == types.Int64
9271
10315
  }
9272
10316
 
10317
+ func isRuntimeWideIntegerType(typ types.Type) bool {
10318
+ if isFixedWideIntegerType(typ) {
10319
+ return true
10320
+ }
10321
+ bits, ok := unsignedIntegerBits(typ)
10322
+ return ok && bits > 32
10323
+ }
10324
+
9273
10325
  func isRuneSliceType(typ types.Type) bool {
9274
10326
  slice, ok := types.Unalias(typ).Underlying().(*types.Slice)
9275
10327
  return ok && isRuneType(slice.Elem())
@@ -9355,8 +10407,7 @@ func (o *LoweringOwner) functionAsync(ctx lowerFileContext, fn *types.Func) bool
9355
10407
  if fn == nil || ctx.model == nil {
9356
10408
  return false
9357
10409
  }
9358
- semFn := semanticFunctionFor(ctx.model, fn)
9359
- return semFn != nil && semFn.async
10410
+ return ctx.model.functionAsync(fn)
9360
10411
  }
9361
10412
 
9362
10413
  func (o *LoweringOwner) callNeedsAwait(ctx lowerFileContext, fun ast.Expr) bool {
@@ -9505,6 +10556,18 @@ func (o *LoweringOwner) inferGenericTypeArg(
9505
10556
  }
9506
10557
  return
9507
10558
  }
10559
+ if paramNamed, ok := types.Unalias(paramType).(*types.Named); ok {
10560
+ if argNamed, ok := types.Unalias(argType).(*types.Named); ok &&
10561
+ namedOriginsEqual(paramNamed, argNamed) {
10562
+ paramArgs := paramNamed.TypeArgs()
10563
+ argArgs := argNamed.TypeArgs()
10564
+ if paramArgs != nil && argArgs != nil {
10565
+ for idx := range min(paramArgs.Len(), argArgs.Len()) {
10566
+ o.inferGenericTypeArg(inferred, paramArgs.At(idx), argArgs.At(idx))
10567
+ }
10568
+ }
10569
+ }
10570
+ }
9508
10571
  switch param := types.Unalias(paramType).Underlying().(type) {
9509
10572
  case *types.Slice:
9510
10573
  if arg, ok := types.Unalias(argType).Underlying().(*types.Slice); ok {
@@ -9517,6 +10580,24 @@ func (o *LoweringOwner) inferGenericTypeArg(
9517
10580
  }
9518
10581
  }
9519
10582
 
10583
+ func namedOriginsEqual(a, b *types.Named) bool {
10584
+ if a == nil || b == nil {
10585
+ return false
10586
+ }
10587
+ aOrigin := a.Origin()
10588
+ if aOrigin == nil {
10589
+ aOrigin = a
10590
+ }
10591
+ bOrigin := b.Origin()
10592
+ if bOrigin == nil {
10593
+ bOrigin = b
10594
+ }
10595
+ if aOrigin.Obj() == nil || bOrigin.Obj() == nil {
10596
+ return aOrigin == bOrigin
10597
+ }
10598
+ return aOrigin.Obj() == bOrigin.Obj()
10599
+ }
10600
+
9520
10601
  func (o *LoweringOwner) genericTypeDescriptorExpr(ctx lowerFileContext, typ types.Type) string {
9521
10602
  if typeParam, ok := types.Unalias(typ).(*types.TypeParam); ok && typeParamInScope(ctx, typeParam) {
9522
10603
  return "__typeArgs?.[" + strconv.Quote(typeParam.Obj().Name()) + "] ?? { type: " +
@@ -9560,7 +10641,12 @@ func (o *LoweringOwner) genericMethodDescriptorsForType(
9560
10641
  if sig, _ := method.Type().(*types.Signature); sig != nil {
9561
10642
  if recv := sig.Recv(); recv != nil {
9562
10643
  if _, ok := types.Unalias(recv.Type()).Underlying().(*types.Pointer); !ok {
9563
- receiver = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + "(receiver)"
10644
+ if _, ok := types.Unalias(methodSetType).Underlying().(*types.Pointer); ok {
10645
+ receiver = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + "(receiver)"
10646
+ } else {
10647
+ receiver = "(" + o.runtimeOwner.QualifiedHelper(RuntimeHelperIsVarRef) +
10648
+ "(receiver) ? receiver.value : receiver)"
10649
+ }
9564
10650
  }
9565
10651
  }
9566
10652
  }
@@ -9590,9 +10676,9 @@ func namedNonStructMethodSetType(typ types.Type) (*types.Named, types.Type) {
9590
10676
 
9591
10677
  func methodFunctionName(receiver *types.Named, method string) string {
9592
10678
  if receiver == nil || receiver.Obj() == nil {
9593
- return method
10679
+ return safeIdentifier(method)
9594
10680
  }
9595
- return receiver.Obj().Name() + "_" + method
10681
+ return safeIdentifier(receiver.Obj().Name()) + "_" + safeIdentifier(method)
9596
10682
  }
9597
10683
 
9598
10684
  func methodReceiverNamedType(obj types.Object) *types.Named {
@@ -9629,7 +10715,7 @@ func (o *LoweringOwner) namedTypeExpr(ctx lowerFileContext, named *types.Named)
9629
10715
  if named == nil || named.Obj() == nil {
9630
10716
  return "unknown"
9631
10717
  }
9632
- baseName := named.Obj().Name()
10718
+ baseName := safeIdentifier(named.Obj().Name())
9633
10719
  if alias := ctx.localAliases[named.Obj()]; alias != "" {
9634
10720
  baseName = alias + "." + baseName
9635
10721
  } else if named.Obj().Pkg() != nil {
@@ -9692,11 +10778,30 @@ func runtimeNamedTypeName(named *types.Named) string {
9692
10778
  }
9693
10779
 
9694
10780
  func goRuntimeTypeString(typ types.Type) string {
9695
- return types.TypeString(typ, func(pkg *types.Package) string {
10781
+ return types.TypeString(runtimeIdentityType(typ), func(pkg *types.Package) string {
9696
10782
  return pkg.Name()
9697
10783
  })
9698
10784
  }
9699
10785
 
10786
+ func runtimeIdentityType(typ types.Type) types.Type {
10787
+ switch typed := typ.(type) {
10788
+ case *types.Alias:
10789
+ return runtimeIdentityType(types.Unalias(typed))
10790
+ case *types.Pointer:
10791
+ return types.NewPointer(runtimeIdentityType(typed.Elem()))
10792
+ case *types.Slice:
10793
+ return types.NewSlice(runtimeIdentityType(typed.Elem()))
10794
+ case *types.Array:
10795
+ return types.NewArray(runtimeIdentityType(typed.Elem()), typed.Len())
10796
+ case *types.Map:
10797
+ return types.NewMap(runtimeIdentityType(typed.Key()), runtimeIdentityType(typed.Elem()))
10798
+ case *types.Chan:
10799
+ return types.NewChan(typed.Dir(), runtimeIdentityType(typed.Elem()))
10800
+ default:
10801
+ return typ
10802
+ }
10803
+ }
10804
+
9700
10805
  func basicRuntimeName(basic *types.Basic) string {
9701
10806
  if basic == nil {
9702
10807
  return "unknown"
@@ -9706,6 +10811,32 @@ func basicRuntimeName(basic *types.Basic) string {
9706
10811
  return "bool"
9707
10812
  case types.String:
9708
10813
  return "string"
10814
+ case types.Int:
10815
+ return "int"
10816
+ case types.Int8:
10817
+ return "int8"
10818
+ case types.Int16:
10819
+ return "int16"
10820
+ case types.Int32:
10821
+ return "int32"
10822
+ case types.Int64:
10823
+ return "int64"
10824
+ case types.Uint:
10825
+ return "uint"
10826
+ case types.Uint8:
10827
+ return "uint8"
10828
+ case types.Uint16:
10829
+ return "uint16"
10830
+ case types.Uint32:
10831
+ return "uint32"
10832
+ case types.Uint64:
10833
+ return "uint64"
10834
+ case types.Uintptr:
10835
+ return "uintptr"
10836
+ case types.Float32:
10837
+ return "float32"
10838
+ case types.Float64:
10839
+ return "float64"
9709
10840
  case types.Complex64:
9710
10841
  return "complex64"
9711
10842
  case types.Complex128: