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.
- package/compiler/lowered-program.go +1 -0
- package/compiler/lowering.go +715 -44
- package/compiler/override-registry_test.go +43 -0
- package/compiler/skeleton_test.go +464 -12
- package/compiler/typescript-emitter.go +28 -2
- package/dist/gs/builtin/channel.js +36 -9
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/type.js +8 -3
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.d.ts +7 -5
- package/dist/gs/bytes/bytes.gs.js +10 -4
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/crypto/sha1/index.d.ts +5 -0
- package/dist/gs/crypto/sha1/index.js +106 -0
- package/dist/gs/crypto/sha1/index.js.map +1 -0
- package/dist/gs/fmt/fmt.d.ts +1 -1
- package/dist/gs/fmt/fmt.js +64 -3
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/io/io.d.ts +8 -5
- package/dist/gs/io/io.js +20 -2
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/net/http/httptest/index.js +7 -5
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +8 -0
- package/dist/gs/net/http/index.js +139 -10
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/os/zero_copy_posix.gs.js +1 -1
- package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
- package/gs/builtin/channel.ts +47 -9
- package/gs/builtin/runtime-contract.test.ts +33 -0
- package/gs/builtin/type.ts +12 -3
- package/gs/bytes/bytes.gs.ts +19 -10
- package/gs/bytes/bytes.test.ts +17 -0
- package/gs/context/context.test.ts +5 -1
- package/gs/crypto/sha1/index.test.ts +28 -0
- package/gs/crypto/sha1/index.ts +130 -0
- package/gs/crypto/sha1/meta.json +8 -0
- package/gs/fmt/fmt.test.ts +20 -0
- package/gs/fmt/fmt.ts +75 -5
- package/gs/github.com/aperturerobotics/util/conc/index.test.ts +1 -1
- package/gs/io/io.test.ts +64 -0
- package/gs/io/io.ts +30 -12
- package/gs/net/http/httptest/index.test.ts +34 -2
- package/gs/net/http/httptest/index.ts +23 -8
- package/gs/net/http/index.test.ts +30 -0
- package/gs/net/http/index.ts +159 -10
- package/gs/os/zero_copy_posix.gs.ts +1 -2
- package/gs/sync/meta.json +1 -0
- package/package.json +1 -1
package/compiler/lowering.go
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
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:
|
|
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
|
|
453
|
-
|
|
454
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 = "
|
|
872
|
-
code = "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1239
|
+
if lazy {
|
|
1240
|
+
setterTarget = packageVarGetterName(name.Name) + "().value"
|
|
1241
|
+
} else {
|
|
1242
|
+
setterTarget += ".value"
|
|
1243
|
+
}
|
|
911
1244
|
}
|
|
912
|
-
|
|
913
|
-
|
|
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: "
|
|
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 = "
|
|
1307
|
-
code = "
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 "",
|
|
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
|
|
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
|
-
|
|
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"
|