goscript 0.1.2 → 0.1.3

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 (49) hide show
  1. package/compiler/lowered-program.go +1 -0
  2. package/compiler/lowering.go +715 -44
  3. package/compiler/override-registry_test.go +43 -0
  4. package/compiler/skeleton_test.go +464 -12
  5. package/compiler/typescript-emitter.go +28 -2
  6. package/dist/gs/builtin/channel.js +36 -9
  7. package/dist/gs/builtin/channel.js.map +1 -1
  8. package/dist/gs/builtin/type.js +8 -3
  9. package/dist/gs/builtin/type.js.map +1 -1
  10. package/dist/gs/bytes/bytes.gs.d.ts +7 -5
  11. package/dist/gs/bytes/bytes.gs.js +10 -4
  12. package/dist/gs/bytes/bytes.gs.js.map +1 -1
  13. package/dist/gs/crypto/sha1/index.d.ts +5 -0
  14. package/dist/gs/crypto/sha1/index.js +106 -0
  15. package/dist/gs/crypto/sha1/index.js.map +1 -0
  16. package/dist/gs/fmt/fmt.d.ts +1 -1
  17. package/dist/gs/fmt/fmt.js +64 -3
  18. package/dist/gs/fmt/fmt.js.map +1 -1
  19. package/dist/gs/io/io.d.ts +8 -5
  20. package/dist/gs/io/io.js +20 -2
  21. package/dist/gs/io/io.js.map +1 -1
  22. package/dist/gs/net/http/httptest/index.js +7 -5
  23. package/dist/gs/net/http/httptest/index.js.map +1 -1
  24. package/dist/gs/net/http/index.d.ts +8 -0
  25. package/dist/gs/net/http/index.js +139 -10
  26. package/dist/gs/net/http/index.js.map +1 -1
  27. package/dist/gs/os/zero_copy_posix.gs.js +1 -1
  28. package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
  29. package/gs/builtin/channel.ts +47 -9
  30. package/gs/builtin/runtime-contract.test.ts +33 -0
  31. package/gs/builtin/type.ts +12 -3
  32. package/gs/bytes/bytes.gs.ts +19 -10
  33. package/gs/bytes/bytes.test.ts +17 -0
  34. package/gs/context/context.test.ts +5 -1
  35. package/gs/crypto/sha1/index.test.ts +28 -0
  36. package/gs/crypto/sha1/index.ts +130 -0
  37. package/gs/crypto/sha1/meta.json +8 -0
  38. package/gs/fmt/fmt.test.ts +20 -0
  39. package/gs/fmt/fmt.ts +75 -5
  40. package/gs/github.com/aperturerobotics/util/conc/index.test.ts +1 -1
  41. package/gs/io/io.test.ts +64 -0
  42. package/gs/io/io.ts +30 -12
  43. package/gs/net/http/httptest/index.test.ts +34 -2
  44. package/gs/net/http/httptest/index.ts +23 -8
  45. package/gs/net/http/index.test.ts +30 -0
  46. package/gs/net/http/index.ts +159 -10
  47. package/gs/os/zero_copy_posix.gs.ts +1 -2
  48. package/gs/sync/meta.json +1 -0
  49. 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 {
@@ -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 + " = undefined as unknown as " + 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,6 +1316,88 @@ 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
@@ -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 {
@@ -1493,12 +2091,13 @@ func (o *LoweringOwner) lowerTypeSpec(ctx lowerFileContext, spec *ast.TypeSpec)
1493
2091
  if signature, ok := named.Underlying().(*types.Signature); ok {
1494
2092
  loweredType = o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
1495
2093
  }
1496
- code := "type " + semType.name + " = " + loweredType
2094
+ typeName := safeIdentifier(semType.name)
2095
+ code := "type " + typeName + " = " + loweredType
1497
2096
  typeIndexExport := ""
1498
2097
  if ctx.topLevel {
1499
2098
  code = "export " + code
1500
2099
  if ast.IsExported(semType.name) {
1501
- typeIndexExport = semType.name
2100
+ typeIndexExport = typeName
1502
2101
  }
1503
2102
  }
1504
2103
  return loweredDecl{code: code, typeIndexExport: typeIndexExport}, nil
@@ -1506,12 +2105,13 @@ func (o *LoweringOwner) lowerTypeSpec(ctx lowerFileContext, spec *ast.TypeSpec)
1506
2105
 
1507
2106
  func (o *LoweringOwner) lowerInterfaceType(ctx lowerFileContext, semType *semanticType, iface *types.Interface) loweredDecl {
1508
2107
  iface.Complete()
1509
- code := "type " + semType.name + " = " + o.tsInterfaceType(ctx, iface)
2108
+ typeName := safeIdentifier(semType.name)
2109
+ code := "type " + typeName + " = " + o.tsInterfaceType(ctx, iface)
1510
2110
  typeIndexExport := ""
1511
2111
  if ctx.topLevel {
1512
2112
  code = "export " + code
1513
2113
  if ast.IsExported(semType.name) {
1514
- typeIndexExport = semType.name
2114
+ typeIndexExport = typeName
1515
2115
  }
1516
2116
  }
1517
2117
  code = code + "\n\n" + o.runtimeOwner.QualifiedHelper(RuntimeHelperRegisterInterfaceType) +
@@ -1599,7 +2199,7 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
1599
2199
  lowered := &loweredStruct{
1600
2200
  exported: ctx.topLevel,
1601
2201
  indexExported: ctx.topLevel && ast.IsExported(semType.name),
1602
- name: semType.name,
2202
+ name: safeIdentifier(semType.name),
1603
2203
  typeName: runtimeNamedTypeName(semType.named),
1604
2204
  cloneMethod: "clone",
1605
2205
  }
@@ -3366,12 +3966,20 @@ func (o *LoweringOwner) shortDeclTypeAnnotation(ctx lowerFileContext, lhs ast.Ex
3366
3966
  }
3367
3967
  return ": " + typ
3368
3968
  }
3969
+ if rhs != nil && isIdentLikeExpr(rhs) && isInterfaceType(obj.Type()) {
3970
+ return ": " + o.tsVariableTypeFor(ctx, obj.Type(), ctx.model.needsVarRef[obj])
3971
+ }
3369
3972
  if !shortDeclNeedsTypeAnnotation(obj.Type()) {
3370
3973
  return ""
3371
3974
  }
3372
3975
  return ": " + o.tsVariableTypeFor(ctx, obj.Type(), ctx.model.needsVarRef[obj])
3373
3976
  }
3374
3977
 
3978
+ func isIdentLikeExpr(expr ast.Expr) bool {
3979
+ _, ok := ast.Unparen(expr).(*ast.Ident)
3980
+ return ok
3981
+ }
3982
+
3375
3983
  func shortDeclNeedsTypeAnnotation(typ types.Type) bool {
3376
3984
  switch typed := types.Unalias(typ).Underlying().(type) {
3377
3985
  case *types.Pointer:
@@ -3401,6 +4009,15 @@ func (o *LoweringOwner) lowerTupleTargetAssignmentStmt(
3401
4009
  declare bool,
3402
4010
  ) (loweredStmt, []Diagnostic) {
3403
4011
  if !declare {
4012
+ if index, ok := unwrapParenExpr(lhs).(*ast.IndexExpr); ok && isMapType(ctx.semPkg.source.TypesInfo.TypeOf(index.X)) {
4013
+ targetType := assignmentTargetType(ctx, lhs)
4014
+ value = o.lowerValueForTarget(ctx, lhs, targetType, value)
4015
+ stmts, diagnostics := o.lowerMapIndexUpdateStmts(ctx, index, token.ASSIGN, value, targetType)
4016
+ if len(stmts) != 0 {
4017
+ return stmts[0], diagnostics
4018
+ }
4019
+ return loweredStmt{}, diagnostics
4020
+ }
3404
4021
  if stmt, diagnostics, ok := o.lowerStarTargetAssignmentStmt(ctx, lhs, value); ok {
3405
4022
  return stmt, diagnostics
3406
4023
  }
@@ -5667,6 +6284,9 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
5667
6284
  if alias := ctx.localAliases[obj]; alias != "" {
5668
6285
  if ctx.lazyPackageVars[obj] {
5669
6286
  lazyValue := alias + "." + packageVarGetterName(value) + "()"
6287
+ if (ctx.asyncFunction || ctx.topLevel) && o.packageVarHasAsyncLazyInit(ctx, obj) {
6288
+ lazyValue = "(await " + alias + "." + packageVarInitName(value) + "(), " + lazyValue + ")"
6289
+ }
5670
6290
  if raw {
5671
6291
  return lazyValue
5672
6292
  }
@@ -5682,6 +6302,9 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
5682
6302
  }
5683
6303
  if ctx.lazyPackageVars[obj] {
5684
6304
  lazyValue := packageVarGetterName(value) + "()"
6305
+ if (ctx.asyncFunction || ctx.topLevel) && o.packageVarHasAsyncLazyInit(ctx, obj) {
6306
+ lazyValue = "(await " + packageVarInitName(value) + "(), " + lazyValue + ")"
6307
+ }
5685
6308
  return o.lowerPackageVarReadValue(ctx, obj, lazyValue)
5686
6309
  }
5687
6310
  if obj != nil && ctx.model.needsVarRef[obj] {
@@ -6696,6 +7319,16 @@ func (o *LoweringOwner) lowerPointerReceiverMethodCall(
6696
7319
  return "", nil, false
6697
7320
  }
6698
7321
  receiverExpr, diagnostics := o.lowerExpr(ctx, selector.X)
7322
+ if o.receiverUsesOverridePackage(signature.Recv().Type()) {
7323
+ receiverExpr = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
7324
+ "<" + o.tsTypeFor(ctx, signature.Recv().Type().(*types.Pointer).Elem()) + ">(" + receiverExpr + ")"
7325
+ }
7326
+ if receiverExpr == o.namedTypeExpr(ctx, receiver) {
7327
+ call := o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
7328
+ "<" + o.namedTypeExpr(ctx, receiver) + ">(" + receiverExpr + ")." +
7329
+ methodMemberName(selector.Sel.Name) + "(" + strings.Join(args, ", ") + ")"
7330
+ return call, diagnostics, true
7331
+ }
6699
7332
  callArgs := append([]string{receiverExpr}, args...)
6700
7333
  call := o.namedTypeExpr(ctx, receiver) + ".prototype." + selector.Sel.Name + ".call(" + strings.Join(callArgs, ", ") + ")"
6701
7334
  return call, diagnostics, true
@@ -6813,6 +7446,14 @@ func (o *LoweringOwner) lowerSelectorExpr(ctx lowerFileContext, expr *ast.Select
6813
7446
  if alias := importAliasForPkgName(ctx, pkgName); alias != "" {
6814
7447
  value := alias + "." + expr.Sel.Name
6815
7448
  obj, _ := ctx.semPkg.source.TypesInfo.Uses[expr.Sel].(*types.Var)
7449
+ if o.packageVarIsLazy(ctx, obj) ||
7450
+ o.packageVarNameIsLazy(ctx, pkgName.Imported().Path(), expr.Sel.Name) {
7451
+ value = alias + "." + packageVarGetterName(expr.Sel.Name) + "()"
7452
+ if (ctx.asyncFunction || ctx.topLevel) &&
7453
+ o.packageVarNameHasAsyncLazyInit(ctx, pkgName.Imported().Path(), expr.Sel.Name) {
7454
+ value = "(await " + alias + "." + packageVarInitName(expr.Sel.Name) + "(), " + value + ")"
7455
+ }
7456
+ }
6816
7457
  if obj != nil && packageVarReadNeedsPointerValue(obj.Type()) {
6817
7458
  value = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
6818
7459
  "<" + o.tsNonNilTypeFor(ctx, obj.Type()) + ">(" + value + ")"
@@ -6887,10 +7528,13 @@ func (o *LoweringOwner) packageVarSetterForAssignment(ctx lowerFileContext, expr
6887
7528
  return "", false
6888
7529
  }
6889
7530
  alias := ctx.localAliases[obj]
6890
- if alias == "" {
6891
- return "", false
7531
+ if alias != "" {
7532
+ return alias + "." + packageVarSetterName(ident.Name), true
7533
+ }
7534
+ if ctx.lazyPackageVars[obj] {
7535
+ return packageVarSetterName(ident.Name), true
6892
7536
  }
6893
- return alias + "." + packageVarSetterName(ident.Name), true
7537
+ return "", false
6894
7538
  }
6895
7539
  selector, ok := unwrapParenExpr(expr).(*ast.SelectorExpr)
6896
7540
  if !ok {
@@ -8264,7 +8908,7 @@ func (o *LoweringOwner) lowerStructClone(value string) string {
8264
8908
 
8265
8909
  func (o *LoweringOwner) lowerZeroValueExpr(typ types.Type) string {
8266
8910
  if named := namedStructType(typ); named != nil && isStructValueType(typ) {
8267
- return o.runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue) + "(new " + named.Obj().Name() + "())"
8911
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue) + "(new " + safeIdentifier(named.Obj().Name()) + "())"
8268
8912
  }
8269
8913
  return zeroValueExpr(typ)
8270
8914
  }
@@ -8789,6 +9433,9 @@ func (o *LoweringOwner) tsNonNilTypeFor(ctx lowerFileContext, typ types.Type) st
8789
9433
  }
8790
9434
  if named, ok := types.Unalias(typ).(*types.Named); ok {
8791
9435
  if _, ok := named.Underlying().(*types.Interface); ok {
9436
+ if !ctx.canReferenceNamedType(named) {
9437
+ return "any"
9438
+ }
8792
9439
  return "Exclude<" + o.namedTypeExpr(ctx, named) + ", null>"
8793
9440
  }
8794
9441
  }
@@ -8851,7 +9498,7 @@ func zeroValueExpr(typ types.Type) string {
8851
9498
  return "undefined"
8852
9499
  }
8853
9500
  if named := namedStructType(typ); named != nil && isStructValueType(typ) {
8854
- return "new " + named.Obj().Name() + "()"
9501
+ return "new " + safeIdentifier(named.Obj().Name()) + "()"
8855
9502
  }
8856
9503
  switch typed := types.Unalias(typ).Underlying().(type) {
8857
9504
  case *types.Basic:
@@ -9560,7 +10207,12 @@ func (o *LoweringOwner) genericMethodDescriptorsForType(
9560
10207
  if sig, _ := method.Type().(*types.Signature); sig != nil {
9561
10208
  if recv := sig.Recv(); recv != nil {
9562
10209
  if _, ok := types.Unalias(recv.Type()).Underlying().(*types.Pointer); !ok {
9563
- receiver = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + "(receiver)"
10210
+ if _, ok := types.Unalias(methodSetType).Underlying().(*types.Pointer); ok {
10211
+ receiver = o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) + "(receiver)"
10212
+ } else {
10213
+ receiver = "(" + o.runtimeOwner.QualifiedHelper(RuntimeHelperIsVarRef) +
10214
+ "(receiver) ? receiver.value : receiver)"
10215
+ }
9564
10216
  }
9565
10217
  }
9566
10218
  }
@@ -9590,9 +10242,9 @@ func namedNonStructMethodSetType(typ types.Type) (*types.Named, types.Type) {
9590
10242
 
9591
10243
  func methodFunctionName(receiver *types.Named, method string) string {
9592
10244
  if receiver == nil || receiver.Obj() == nil {
9593
- return method
10245
+ return safeIdentifier(method)
9594
10246
  }
9595
- return receiver.Obj().Name() + "_" + method
10247
+ return safeIdentifier(receiver.Obj().Name()) + "_" + safeIdentifier(method)
9596
10248
  }
9597
10249
 
9598
10250
  func methodReceiverNamedType(obj types.Object) *types.Named {
@@ -9629,7 +10281,7 @@ func (o *LoweringOwner) namedTypeExpr(ctx lowerFileContext, named *types.Named)
9629
10281
  if named == nil || named.Obj() == nil {
9630
10282
  return "unknown"
9631
10283
  }
9632
- baseName := named.Obj().Name()
10284
+ baseName := safeIdentifier(named.Obj().Name())
9633
10285
  if alias := ctx.localAliases[named.Obj()]; alias != "" {
9634
10286
  baseName = alias + "." + baseName
9635
10287
  } else if named.Obj().Pkg() != nil {
@@ -9692,11 +10344,30 @@ func runtimeNamedTypeName(named *types.Named) string {
9692
10344
  }
9693
10345
 
9694
10346
  func goRuntimeTypeString(typ types.Type) string {
9695
- return types.TypeString(typ, func(pkg *types.Package) string {
10347
+ return types.TypeString(runtimeIdentityType(typ), func(pkg *types.Package) string {
9696
10348
  return pkg.Name()
9697
10349
  })
9698
10350
  }
9699
10351
 
10352
+ func runtimeIdentityType(typ types.Type) types.Type {
10353
+ switch typed := typ.(type) {
10354
+ case *types.Alias:
10355
+ return runtimeIdentityType(types.Unalias(typed))
10356
+ case *types.Pointer:
10357
+ return types.NewPointer(runtimeIdentityType(typed.Elem()))
10358
+ case *types.Slice:
10359
+ return types.NewSlice(runtimeIdentityType(typed.Elem()))
10360
+ case *types.Array:
10361
+ return types.NewArray(runtimeIdentityType(typed.Elem()), typed.Len())
10362
+ case *types.Map:
10363
+ return types.NewMap(runtimeIdentityType(typed.Key()), runtimeIdentityType(typed.Elem()))
10364
+ case *types.Chan:
10365
+ return types.NewChan(typed.Dir(), runtimeIdentityType(typed.Elem()))
10366
+ default:
10367
+ return typ
10368
+ }
10369
+ }
10370
+
9700
10371
  func basicRuntimeName(basic *types.Basic) string {
9701
10372
  if basic == nil {
9702
10373
  return "unknown"