Skip to content

Commit 36c8c11

Browse files
Working on package analysis
1 parent cbf9b58 commit 36c8c11

File tree

6 files changed

+152
-135
lines changed

6 files changed

+152
-135
lines changed

build/build.go

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,9 @@ import (
2727
"github.com/fsnotify/fsnotify"
2828
"github.com/gopherjs/gopherjs/compiler"
2929
"github.com/gopherjs/gopherjs/compiler/astutil"
30-
"github.com/gopherjs/gopherjs/compiler/internal/typeparams"
3130
"github.com/gopherjs/gopherjs/compiler/jsFile"
3231
"github.com/gopherjs/gopherjs/compiler/sources"
3332
"github.com/gopherjs/gopherjs/internal/errorList"
34-
"github.com/gopherjs/gopherjs/internal/experiments"
3533
"github.com/gopherjs/gopherjs/internal/testmain"
3634
log "github.com/sirupsen/logrus"
3735

@@ -938,10 +936,11 @@ func (s *Session) BuildProject(pkg *PackageData) (*compiler.Archive, error) {
938936
return nil, err
939937
}
940938

941-
// TODO(grantnelson-wf): Handle newRootCtx changes
939+
// Propagate the analysis information to all packages.
940+
compiler.PropagateAnalysis(s.sources)
942941

943942
// Compile the project into Archives containing the generated JS.
944-
return s.compilePackages(srcs)
943+
return s.compilePackages(srcs, tContext)
945944
}
946945

947946
func (s *Session) loadTestPackage(pkg *PackageData) (*sources.Sources, error) {
@@ -1109,43 +1108,32 @@ func (s *Session) loadPackages(pkg *PackageData) (*sources.Sources, error) {
11091108
return srcs, nil
11101109
}
11111110

1112-
type importContext struct {
1113-
s *Session
1114-
dir string
1115-
tContext *types.Context
1116-
}
1117-
1118-
func (ic *importContext) Import(path string) (*types.Package, error) {
1119-
1120-
}
1121-
11221111
func (s *Session) prepareSources(srcs *sources.Sources, tContext *types.Context) error {
1123-
ic := &importContext{
1124-
s: s,
1125-
dir: srcs.Dir,
1126-
tContext: tContext,
1127-
}
1128-
1129-
if err := srcs.TypeCheck(ic, sizes32, tContext); err != nil {
1130-
return err
1131-
}
1112+
importer := func(path string) (*sources.Sources, error) {
1113+
importPath, err := s.getImportPath(path, srcs.Dir)
1114+
if err != nil {
1115+
return nil, err
1116+
}
11321117

1133-
if genErr := typeparams.RequiresGenericsSupport(srcs.TypeInfo); genErr != nil && !experiments.Env.Generics {
1134-
return fmt.Errorf("package %s requires generics support (https://github.com/gopherjs/gopherjs/issues/1013): %w", srcs.ImportPath, genErr)
1135-
}
1118+
if srcs, ok := s.sources[importPath]; ok {
1119+
if srcs.Package == nil {
1120+
err = s.prepareSources(srcs, tContext)
1121+
if err != nil {
1122+
return nil, err
1123+
}
1124+
}
1125+
return srcs, nil
1126+
}
11361127

1137-
// Extract all go:linkname compiler directives from the package source.
1138-
if err := srcs.ParseGoLinknames(); err != nil {
1139-
return err
1128+
return nil, fmt.Errorf(`sources for %q not found`, importPath)
11401129
}
11411130

1142-
srcs.Simplify()
1143-
return nil
1131+
return compiler.PrepareSources(srcs, importer, tContext)
11441132
}
11451133

1146-
func (s *Session) compilePackages(rootSrcs *sources.Sources) (*compiler.Archive, error) {
1134+
func (s *Session) compilePackages(rootSrcs *sources.Sources, tContext *types.Context) (*compiler.Archive, error) {
11471135
for _, srcs := range s.sources {
1148-
archive, err := compiler.Compile(*srcs, s.options.Minify)
1136+
archive, err := compiler.Compile(*srcs, tContext, s.options.Minify)
11491137
if err != nil {
11501138
return nil, err
11511139
}
@@ -1199,12 +1187,7 @@ func (s *Session) ImportResolverFor(srcDir string) func(string) (*compiler.Archi
11991187
return archive, nil
12001188
}
12011189

1202-
// The archive hasn't been compiled yet so compile it with the sources.
1203-
if srcs, ok := s.sources[importPath]; ok {
1204-
return s.compilePackages(srcs)
1205-
}
1206-
1207-
return nil, fmt.Errorf(`sources for %q not found`, importPath)
1190+
return nil, fmt.Errorf(`archive for %q not found`, importPath)
12081191
}
12091192
}
12101193

compiler/internal/analysis/info.go

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,12 @@ type Info struct {
5858
funcLitInfos map[*ast.FuncLit][]*FuncInfo
5959
InitFuncInfo *FuncInfo // Context for package variable initialization.
6060

61-
isImportedBlocking func(typeparams.Instance) bool // For functions from other packages.
62-
allInfos []*FuncInfo
61+
infoImporter InfoImporter // For functions from other packages.
62+
allInfos []*FuncInfo
6363
}
6464

65+
type InfoImporter func(path string) (*Info, error)
66+
6567
func (info *Info) newFuncInfo(n ast.Node, obj types.Object, typeArgs typesutil.TypeList, resolver *typeparams.Resolver) *FuncInfo {
6668
funcInfo := &FuncInfo{
6769
pkgInfo: info,
@@ -132,11 +134,16 @@ func (info *Info) newFuncInfoInstances(fd *ast.FuncDecl) []*FuncInfo {
132134
}
133135

134136
// IsBlocking returns true if the function may contain blocking calls or operations.
135-
// If inst is from a different package, this will use the isImportedBlocking
137+
// If inst is from a different package, this will use the getImportInfo function
136138
// to lookup the information from the other package.
137139
func (info *Info) IsBlocking(inst typeparams.Instance) bool {
138140
if inst.Object.Pkg() != info.Pkg {
139-
return info.isImportedBlocking(inst)
141+
path := inst.Object.Pkg().Path()
142+
otherInfo, err := info.infoImporter(path)
143+
if err != nil {
144+
panic(fmt.Errorf(`failed to get info for package %q: %v`, path, err))
145+
}
146+
return otherInfo.IsBlocking(inst)
140147
}
141148
if funInfo := info.FuncInfo(inst); funInfo != nil {
142149
return funInfo.IsBlocking()
@@ -174,16 +181,21 @@ func (info *Info) VarsWithInitializers() map[*types.Var]bool {
174181
return result
175182
}
176183

177-
func AnalyzePkg(files []*ast.File, fileSet *token.FileSet, typesInfo *types.Info, typeCtx *types.Context, typesPkg *types.Package, instanceSets *typeparams.PackageInstanceSets, isBlocking func(typeparams.Instance) bool) *Info {
184+
// AnalyzePkg analyzes the given package for blocking calls, defers, etc.
185+
//
186+
// Note that at the end of this call the analysis information
187+
// has NOT been propagated across packages yet. Once all the packages
188+
// have been analyzed, call PropagateAnalysis to propagate the information.
189+
func AnalyzePkg(files []*ast.File, fileSet *token.FileSet, typesInfo *types.Info, typeCtx *types.Context, typesPkg *types.Package, instanceSets *typeparams.PackageInstanceSets, infoImporter InfoImporter) *Info {
178190
info := &Info{
179-
Info: typesInfo,
180-
Pkg: typesPkg,
181-
typeCtx: typeCtx,
182-
instanceSets: instanceSets,
183-
HasPointer: make(map[*types.Var]bool),
184-
isImportedBlocking: isBlocking,
185-
funcInstInfos: new(typeparams.InstanceMap[*FuncInfo]),
186-
funcLitInfos: make(map[*ast.FuncLit][]*FuncInfo),
191+
Info: typesInfo,
192+
Pkg: typesPkg,
193+
typeCtx: typeCtx,
194+
instanceSets: instanceSets,
195+
HasPointer: make(map[*types.Var]bool),
196+
infoImporter: infoImporter,
197+
funcInstInfos: new(typeparams.InstanceMap[*FuncInfo]),
198+
funcLitInfos: make(map[*ast.FuncLit][]*FuncInfo),
187199
}
188200
info.InitFuncInfo = info.newFuncInfo(nil, nil, nil, nil)
189201

@@ -193,13 +205,25 @@ func AnalyzePkg(files []*ast.File, fileSet *token.FileSet, typesInfo *types.Info
193205
ast.Walk(info.InitFuncInfo, file)
194206
}
195207

208+
return info
209+
}
210+
211+
// PropagateAnalysis will propagate analysis information across package
212+
// boundaries to finish the analysis of a whole project.
213+
func PropagateAnalysis(allInfo []*Info) {
196214
done := false
197215
for !done {
198-
done = info.propagateFunctionBlocking()
216+
done = true
217+
for _, info := range allInfo {
218+
if !info.propagateFunctionBlocking() {
219+
done = false
220+
}
221+
}
199222
}
200223

201-
info.propagateControlStatementBlocking()
202-
return info
224+
for _, info := range allInfo {
225+
info.propagateControlStatementBlocking()
226+
}
203227
}
204228

205229
// propagateFunctionBlocking propagates information about blocking calls

compiler/internal/analysis/info_test.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package analysis
22

33
import (
4+
"fmt"
45
"go/ast"
56
"go/types"
67
"sort"
@@ -1639,11 +1640,10 @@ func newBlockingTest(t *testing.T, src string) *blockingTest {
16391640
testInfo, testPkg := f.Check(`pkg/test`, file)
16401641
tc.Scan(testPkg, file)
16411642

1642-
isImportBlocking := func(i typeparams.Instance) bool {
1643-
t.Fatalf(`isImportBlocking should not be called in this test, called with %v`, i)
1644-
return true
1643+
getImportInfo := func(path string) (*Info, error) {
1644+
return nil, fmt.Errorf(`getImportInfo should not be called in this test, called with %v`, path)
16451645
}
1646-
pkgInfo := AnalyzePkg([]*ast.File{file}, f.FileSet, testInfo, types.NewContext(), testPkg, tc.Instances, isImportBlocking)
1646+
pkgInfo := AnalyzePkg([]*ast.File{file}, f.FileSet, testInfo, types.NewContext(), testPkg, tc.Instances, getImportInfo)
16471647

16481648
return &blockingTest{
16491649
f: f,
@@ -1660,13 +1660,12 @@ func newBlockingTestWithOtherPackage(t *testing.T, testSrc string, otherSrc stri
16601660
Instances: &typeparams.PackageInstanceSets{},
16611661
}
16621662

1663-
pkgInfo := map[*types.Package]*Info{}
1664-
isImportBlocking := func(i typeparams.Instance) bool {
1665-
if info, ok := pkgInfo[i.Object.Pkg()]; ok {
1666-
return info.IsBlocking(i)
1663+
pkgInfo := map[string]*Info{}
1664+
getImportInfo := func(path string) (*Info, error) {
1665+
if info, ok := pkgInfo[path]; ok {
1666+
return info, nil
16671667
}
1668-
t.Fatalf(`unexpected package in isImportBlocking for %v`, i)
1669-
return true
1668+
return nil, fmt.Errorf(`unexpected package in getImportInfo for %v`, path)
16701669
}
16711670

16721671
otherFile := f.Parse(`other.go`, otherSrc)
@@ -1677,11 +1676,11 @@ func newBlockingTestWithOtherPackage(t *testing.T, testSrc string, otherSrc stri
16771676
_, testPkg := f.Check(`pkg/test`, testFile)
16781677
tc.Scan(testPkg, testFile)
16791678

1680-
otherPkgInfo := AnalyzePkg([]*ast.File{otherFile}, f.FileSet, f.Info, types.NewContext(), otherPkg, tc.Instances, isImportBlocking)
1681-
pkgInfo[otherPkg] = otherPkgInfo
1679+
otherPkgInfo := AnalyzePkg([]*ast.File{otherFile}, f.FileSet, f.Info, types.NewContext(), otherPkg, tc.Instances, getImportInfo)
1680+
pkgInfo[otherPkg.Path()] = otherPkgInfo
16821681

1683-
testPkgInfo := AnalyzePkg([]*ast.File{testFile}, f.FileSet, f.Info, types.NewContext(), testPkg, tc.Instances, isImportBlocking)
1684-
pkgInfo[testPkg] = testPkgInfo
1682+
testPkgInfo := AnalyzePkg([]*ast.File{testFile}, f.FileSet, f.Info, types.NewContext(), testPkg, tc.Instances, getImportInfo)
1683+
pkgInfo[testPkg.Path()] = testPkgInfo
16851684

16861685
return &blockingTest{
16871686
f: f,

0 commit comments

Comments
 (0)