@@ -613,6 +613,115 @@ func TestDeclNaming_VarsAndTypes(t *testing.T) {
613613 )
614614}
615615
616+ func Test_CrossPackageAnalysis (t * testing.T ) {
617+ src1 := `
618+ package main
619+ import "github.com/gopherjs/gopherjs/compiler/stable"
620+
621+ func main() {
622+ m := map[string]int{
623+ "one": 1,
624+ "two": 2,
625+ "three": 3,
626+ }
627+ stable.Print(m)
628+ }`
629+ src2 := `
630+ package collections
631+ import "github.com/gopherjs/gopherjs/compiler/cmp"
632+
633+ func Keys[K cmp.Ordered, V any, M ~map[K]V](m M) []K {
634+ keys := make([]K, 0, len(m))
635+ for k := range m {
636+ keys = append(keys, k)
637+ }
638+ return keys
639+ }`
640+ src3 := `
641+ package collections
642+ import "github.com/gopherjs/gopherjs/compiler/cmp"
643+
644+ func Values[K cmp.Ordered, V any, M ~map[K]V](m M) []V {
645+ values := make([]V, 0, len(m))
646+ for _, v := range m {
647+ values = append(values, v)
648+ }
649+ return values
650+ }`
651+ src4 := `
652+ package sorts
653+ import "github.com/gopherjs/gopherjs/compiler/cmp"
654+
655+ func Pair[K cmp.Ordered, V any, SK ~[]K, SV ~[]V](k SK, v SV) {
656+ Bubble(len(k),
657+ func(i, j int) bool { return k[i] < k[j] },
658+ func(i, j int) { k[i], v[i], k[j], v[j] = k[j], v[j], k[i], v[i] })
659+ }
660+
661+ func Bubble(length int, less func(i, j int) bool, swap func(i, j int)) {
662+ for i := 0; i < length; i++ {
663+ for j := i + 1; j < length; j++ {
664+ if less(j, i) {
665+ swap(i, j)
666+ }
667+ }
668+ }
669+ }`
670+ src5 := `
671+ package stable
672+ import (
673+ "github.com/gopherjs/gopherjs/compiler/collections"
674+ "github.com/gopherjs/gopherjs/compiler/sorts"
675+ "github.com/gopherjs/gopherjs/compiler/cmp"
676+ )
677+
678+ func Print[K cmp.Ordered, V any, M ~map[K]V](m M) {
679+ keys := collections.Keys(m)
680+ values := collections.Values(m)
681+ sorts.Pair(keys, values)
682+ for i, k := range keys {
683+ println(i, k, values[i])
684+ }
685+ }`
686+ src6 := `
687+ package cmp
688+ type Ordered interface { ~int | ~uint | ~float64 | ~string }`
689+
690+ root := srctesting .ParseSources (t ,
691+ []srctesting.Source {
692+ {Name : `main.go` , Contents : []byte (src1 )},
693+ },
694+ []srctesting.Source {
695+ {Name : `collections/keys.go` , Contents : []byte (src2 )},
696+ {Name : `collections/values.go` , Contents : []byte (src3 )},
697+ {Name : `sorts/sorts.go` , Contents : []byte (src4 )},
698+ {Name : `stable/print.go` , Contents : []byte (src5 )},
699+ {Name : `cmp/ordered.go` , Contents : []byte (src6 )},
700+ })
701+
702+ archives := compileProject (t , root , false )
703+ checkForDeclFullNames (t , archives ,
704+ // collections
705+ `funcVar:github.com/gopherjs/gopherjs/compiler/collections.Values` ,
706+ `func:github.com/gopherjs/gopherjs/compiler/collections.Values<string, int, map[string]int>` ,
707+ `funcVar:github.com/gopherjs/gopherjs/compiler/collections.Keys` ,
708+ `func:github.com/gopherjs/gopherjs/compiler/collections.Keys<string, int, map[string]int>` ,
709+
710+ // sorts
711+ `funcVar:github.com/gopherjs/gopherjs/compiler/sorts.Pair` ,
712+ `func:github.com/gopherjs/gopherjs/compiler/sorts.Pair<string, int, []string, []int>` ,
713+ `funcVar:github.com/gopherjs/gopherjs/compiler/sorts.Bubble` ,
714+ `func:github.com/gopherjs/gopherjs/compiler/sorts.Bubble` ,
715+
716+ // stable
717+ `funcVar:github.com/gopherjs/gopherjs/compiler/stable.Print` ,
718+ `func:github.com/gopherjs/gopherjs/compiler/stable.Print<string, int, map[string]int>` ,
719+
720+ // main
721+ `init:main` ,
722+ )
723+ }
724+
616725func TestArchiveSelectionAfterSerialization (t * testing.T ) {
617726 src := `
618727 package main
@@ -679,43 +788,43 @@ func compileProject(t *testing.T, root *packages.Package, minify bool) map[strin
679788 pkgMap [pkg .PkgPath ] = pkg
680789 })
681790
682- archiveCache := map [string ]* Archive {}
683- var importContext * ImportContext
684- importContext = & ImportContext {
685- Packages : map [string ]* types.Package {},
686- ImportArchive : func (path string ) (* Archive , error ) {
687- // find in local cache
688- if a , ok := archiveCache [path ]; ok {
689- return a , nil
690- }
691-
692- pkg , ok := pkgMap [path ]
693- if ! ok {
694- t .Fatal (`package not found:` , path )
695- }
696- importContext .Packages [path ] = pkg .Types
697-
698- srcs := sources.Sources {
699- ImportPath : path ,
700- Files : pkg .Syntax ,
701- FileSet : pkg .Fset ,
702- }
791+ allSrcs := map [string ]* sources.Sources {}
792+ for _ , pkg := range pkgMap {
793+ srcs := & sources.Sources {
794+ ImportPath : pkg .PkgPath ,
795+ Dir : `` ,
796+ Files : pkg .Syntax ,
797+ FileSet : pkg .Fset ,
798+ }
799+ allSrcs [pkg .PkgPath ] = srcs
800+ }
703801
704- // compile package
705- a , err := Compile (srcs , importContext , minify )
706- if err != nil {
707- return nil , err
708- }
709- archiveCache [path ] = a
710- return a , nil
711- },
802+ importer := func (path , srcDir string ) (* sources.Sources , error ) {
803+ srcs , ok := allSrcs [path ]
804+ if ! ok {
805+ t .Fatal (`package not found:` , path )
806+ return nil , nil
807+ }
808+ return srcs , nil
712809 }
713810
714- _ , err := importContext .ImportArchive (root .PkgPath )
715- if err != nil {
716- t .Fatal (`failed to compile:` , err )
811+ tContext := types .NewContext ()
812+ sortedSources := make ([]* sources.Sources , 0 , len (allSrcs ))
813+ for _ , srcs := range allSrcs {
814+ sortedSources = append (sortedSources , srcs )
717815 }
718- return archiveCache
816+ sources .SortedSourcesSlice (sortedSources )
817+ PrepareAllSources (sortedSources , importer , tContext )
818+
819+ archives := map [string ]* Archive {}
820+ for _ , srcs := range allSrcs {
821+ a , err := Compile (srcs , tContext , minify )
822+ if err != nil {
823+ t .Fatal (`failed to compile:` , err )
824+ }
825+ archives [srcs .ImportPath ] = a
826+ }
827+ return archives
719828}
720829
721830// newTime creates an arbitrary time.Time offset by the given number of seconds.
@@ -730,6 +839,13 @@ func newTime(seconds float64) time.Time {
730839func reloadCompiledProject (t * testing.T , archives map [string ]* Archive , rootPkgPath string ) map [string ]* Archive {
731840 t .Helper ()
732841
842+ // TODO(grantnelson-wf): The tests using this function are out-of-date
843+ // since they are testing the old archive caching that has been disabled.
844+ // At some point, these tests should be updated to test any new caching
845+ // mechanism that is implemented or removed. As is this function is faking
846+ // the old recursive archive loading that is no longer used since it
847+ // doesn't allow cross package analysis for generings.
848+
733849 buildTime := newTime (5.0 )
734850 serialized := map [string ][]byte {}
735851 for path , a := range archives {
@@ -742,6 +858,10 @@ func reloadCompiledProject(t *testing.T, archives map[string]*Archive, rootPkgPa
742858
743859 srcModTime := newTime (0.0 )
744860 reloadCache := map [string ]* Archive {}
861+ type ImportContext struct {
862+ Packages map [string ]* types.Package
863+ ImportArchive func (path string ) (* Archive , error )
864+ }
745865 var importContext * ImportContext
746866 importContext = & ImportContext {
747867 Packages : map [string ]* types.Package {},
0 commit comments