@@ -16,13 +16,13 @@ import (
1616 "go/scanner"
1717 "go/token"
1818 "go/types"
19- "io"
2019 "log"
2120 "os"
2221 "path/filepath"
2322 "runtime"
2423 "strings"
2524 "sync"
25+ "sync/atomic"
2626 "time"
2727
2828 "golang.org/x/sync/errgroup"
@@ -55,7 +55,7 @@ const (
5555 // NeedName adds Name and PkgPath.
5656 NeedName LoadMode = 1 << iota
5757
58- // NeedFiles adds GoFiles and OtherFiles.
58+ // NeedFiles adds GoFiles, OtherFiles, and IgnoredFiles
5959 NeedFiles
6060
6161 // NeedCompiledGoFiles adds CompiledGoFiles.
@@ -77,7 +77,7 @@ const (
7777 // NeedSyntax adds Syntax and Fset.
7878 NeedSyntax
7979
80- // NeedTypesInfo adds TypesInfo.
80+ // NeedTypesInfo adds TypesInfo and Fset .
8181 NeedTypesInfo
8282
8383 // NeedTypesSizes adds TypesSizes.
@@ -691,18 +691,19 @@ func (p *Package) String() string { return p.ID }
691691// loaderPackage augments Package with state used during the loading phase
692692type loaderPackage struct {
693693 * Package
694- importErrors map [string ]error // maps each bad import to its error
695- loadOnce sync.Once
696- color uint8 // for cycle detection
697- needsrc bool // load from source (Mode >= LoadTypes)
698- needtypes bool // type information is either requested or depended on
699- initial bool // package was matched by a pattern
700- goVersion int // minor version number of go command on PATH
694+ importErrors map [string ]error // maps each bad import to its error
695+ preds []* loaderPackage // packages that import this one
696+ unfinishedSuccs atomic.Int32 // number of direct imports not yet loaded
697+ color uint8 // for cycle detection
698+ needsrc bool // load from source (Mode >= LoadTypes)
699+ needtypes bool // type information is either requested or depended on
700+ initial bool // package was matched by a pattern
701+ goVersion int // minor version number of go command on PATH
701702}
702703
703704// loader holds the working state of a single call to load.
704705type loader struct {
705- pkgs map [string ]* loaderPackage
706+ pkgs map [string ]* loaderPackage // keyed by Package.ID
706707 Config
707708 sizes types.Sizes // non-nil if needed by mode
708709 parseCache map [string ]* parseValue
@@ -764,7 +765,7 @@ func newLoader(cfg *Config) *loader {
764765 ld .requestedMode = ld .Mode
765766 ld .Mode = impliedLoadMode (ld .Mode )
766767
767- if ld .Mode & (NeedTypes | NeedSyntax | NeedTypesInfo ) != 0 {
768+ if ld .Mode & (NeedSyntax | NeedTypes | NeedTypesInfo ) != 0 {
768769 if ld .Fset == nil {
769770 ld .Fset = token .NewFileSet ()
770771 }
@@ -805,7 +806,7 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
805806 exportDataInvalid := len (ld .Overlay ) > 0 || pkg .ExportFile == "" && pkg .PkgPath != "unsafe"
806807 // This package needs type information if the caller requested types and the package is
807808 // either a root, or it's a non-root and the user requested dependencies ...
808- needtypes := (ld .Mode & NeedTypes | NeedTypesInfo != 0 && (rootIndex >= 0 || ld .Mode & NeedDeps != 0 ))
809+ needtypes := (ld .Mode & ( NeedTypes | NeedTypesInfo ) != 0 && (rootIndex >= 0 || ld .Mode & NeedDeps != 0 ))
809810 // This package needs source if the call requested source (or types info, which implies source)
810811 // and the package is either a root, or itas a non- root and the user requested dependencies...
811812 needsrc := ((ld .Mode & (NeedSyntax | NeedTypesInfo ) != 0 && (rootIndex >= 0 || ld .Mode & NeedDeps != 0 )) ||
@@ -830,9 +831,10 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
830831 }
831832 }
832833
833- if ld .Mode & NeedImports != 0 {
834- // Materialize the import graph.
835-
834+ // Materialize the import graph if it is needed (NeedImports),
835+ // or if we'll be using loadPackages (Need{Syntax|Types|TypesInfo}).
836+ var leaves []* loaderPackage // packages with no unfinished successors
837+ if ld .Mode & (NeedImports | NeedSyntax | NeedTypes | NeedTypesInfo ) != 0 {
836838 const (
837839 white = 0 // new
838840 grey = 1 // in progress
@@ -851,63 +853,76 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
851853 // dependency on a package that does. These are the only packages
852854 // for which we load source code.
853855 var stack []* loaderPackage
854- var visit func (lpkg * loaderPackage ) bool
855- visit = func (lpkg * loaderPackage ) bool {
856- switch lpkg .color {
857- case black :
858- return lpkg .needsrc
859- case grey :
856+ var visit func (from , lpkg * loaderPackage ) bool
857+ visit = func (from , lpkg * loaderPackage ) bool {
858+ if lpkg .color == grey {
860859 panic ("internal error: grey node" )
861860 }
862- lpkg .color = grey
863- stack = append (stack , lpkg ) // push
864- stubs := lpkg .Imports // the structure form has only stubs with the ID in the Imports
865- lpkg .Imports = make (map [string ]* Package , len (stubs ))
866- for importPath , ipkg := range stubs {
867- var importErr error
868- imp := ld .pkgs [ipkg .ID ]
869- if imp == nil {
870- // (includes package "C" when DisableCgo)
871- importErr = fmt .Errorf ("missing package: %q" , ipkg .ID )
872- } else if imp .color == grey {
873- importErr = fmt .Errorf ("import cycle: %s" , stack )
861+ if lpkg .color == white {
862+ lpkg .color = grey
863+ stack = append (stack , lpkg ) // push
864+ stubs := lpkg .Imports // the structure form has only stubs with the ID in the Imports
865+ lpkg .Imports = make (map [string ]* Package , len (stubs ))
866+ for importPath , ipkg := range stubs {
867+ var importErr error
868+ imp := ld .pkgs [ipkg .ID ]
869+ if imp == nil {
870+ // (includes package "C" when DisableCgo)
871+ importErr = fmt .Errorf ("missing package: %q" , ipkg .ID )
872+ } else if imp .color == grey {
873+ importErr = fmt .Errorf ("import cycle: %s" , stack )
874+ }
875+ if importErr != nil {
876+ if lpkg .importErrors == nil {
877+ lpkg .importErrors = make (map [string ]error )
878+ }
879+ lpkg .importErrors [importPath ] = importErr
880+ continue
881+ }
882+
883+ if visit (lpkg , imp ) {
884+ lpkg .needsrc = true
885+ }
886+ lpkg .Imports [importPath ] = imp .Package
874887 }
875- if importErr != nil {
876- if lpkg .importErrors == nil {
877- lpkg .importErrors = make (map [string ]error )
888+
889+ // -- postorder --
890+
891+ // Complete type information is required for the
892+ // immediate dependencies of each source package.
893+ if lpkg .needsrc && ld .Mode & NeedTypes != 0 {
894+ for _ , ipkg := range lpkg .Imports {
895+ ld .pkgs [ipkg .ID ].needtypes = true
878896 }
879- lpkg .importErrors [importPath ] = importErr
880- continue
881897 }
882898
883- if visit (imp ) {
884- lpkg .needsrc = true
899+ // NeedTypeSizes causes TypeSizes to be set even
900+ // on packages for which types aren't needed.
901+ if ld .Mode & NeedTypesSizes != 0 {
902+ lpkg .TypesSizes = ld .sizes
885903 }
886- lpkg .Imports [importPath ] = imp .Package
887- }
888904
889- // Complete type information is required for the
890- // immediate dependencies of each source package.
891- if lpkg .needsrc && ld .Mode & NeedTypes != 0 {
892- for _ , ipkg := range lpkg .Imports {
893- ld .pkgs [ipkg .ID ].needtypes = true
905+ // Add packages with no imports directly to the queue of leaves.
906+ if len (lpkg .Imports ) == 0 {
907+ leaves = append (leaves , lpkg )
894908 }
909+
910+ stack = stack [:len (stack )- 1 ] // pop
911+ lpkg .color = black
895912 }
896913
897- // NeedTypeSizes causes TypeSizes to be set even
898- // on packages for which types aren't needed.
899- if ld . Mode & NeedTypesSizes != 0 {
900- lpkg .TypesSizes = ld . sizes
914+ // Add edge from predecessor.
915+ if from != nil {
916+ from . unfinishedSuccs . Add ( + 1 ) // incref
917+ lpkg .preds = append ( lpkg . preds , from )
901918 }
902- stack = stack [:len (stack )- 1 ] // pop
903- lpkg .color = black
904919
905920 return lpkg .needsrc
906921 }
907922
908923 // For each initial package, create its import DAG.
909924 for _ , lpkg := range initial {
910- visit (lpkg )
925+ visit (nil , lpkg )
911926 }
912927
913928 } else {
@@ -920,16 +935,45 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
920935
921936 // Load type data and syntax if needed, starting at
922937 // the initial packages (roots of the import DAG).
923- if ld .Mode & (NeedTypes | NeedSyntax | NeedTypesInfo ) != 0 {
924- var wg sync.WaitGroup
925- for _ , lpkg := range initial {
926- wg .Add (1 )
927- go func (lpkg * loaderPackage ) {
928- ld .loadRecursive (lpkg )
929- wg .Done ()
930- }(lpkg )
938+ if ld .Mode & (NeedSyntax | NeedTypes | NeedTypesInfo ) != 0 {
939+
940+ // We avoid using g.SetLimit to limit concurrency as
941+ // it makes g.Go stop accepting work, which prevents
942+ // workers from enqeuing, and thus finishing, and thus
943+ // allowing the group to make progress: deadlock.
944+ //
945+ // Instead we use the ioLimit and cpuLimit semaphores.
946+ g , _ := errgroup .WithContext (ld .Context )
947+
948+ // enqueues adds a package to the type-checking queue.
949+ // It must have no unfinished successors.
950+ var enqueue func (* loaderPackage )
951+ enqueue = func (lpkg * loaderPackage ) {
952+ g .Go (func () error {
953+ // Parse and type-check.
954+ ld .loadPackage (lpkg )
955+
956+ // Notify each waiting predecessor,
957+ // and enqueue it when it becomes a leaf.
958+ for _ , pred := range lpkg .preds {
959+ if pred .unfinishedSuccs .Add (- 1 ) == 0 { // decref
960+ enqueue (pred )
961+ }
962+ }
963+
964+ return nil
965+ })
966+ }
967+
968+ // Load leaves first, adding new packages
969+ // to the queue as they become leaves.
970+ for _ , leaf := range leaves {
971+ enqueue (leaf )
972+ }
973+
974+ if err := g .Wait (); err != nil {
975+ return nil , err // cancelled
931976 }
932- wg .Wait ()
933977 }
934978
935979 // If the context is done, return its error and
@@ -976,7 +1020,7 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
9761020 if ld .requestedMode & NeedSyntax == 0 {
9771021 ld .pkgs [i ].Syntax = nil
9781022 }
979- if ld .requestedMode & NeedTypes == 0 && ld . requestedMode & NeedSyntax == 0 {
1023+ if ld .requestedMode & ( NeedSyntax | NeedTypes | NeedTypesInfo ) == 0 {
9801024 ld .pkgs [i ].Fset = nil
9811025 }
9821026 if ld .requestedMode & NeedTypesInfo == 0 {
@@ -993,31 +1037,10 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
9931037 return result , nil
9941038}
9951039
996- // loadRecursive loads the specified package and its dependencies,
997- // recursively, in parallel, in topological order.
998- // It is atomic and idempotent.
999- // Precondition: ld.Mode&NeedTypes.
1000- func (ld * loader ) loadRecursive (lpkg * loaderPackage ) {
1001- lpkg .loadOnce .Do (func () {
1002- // Load the direct dependencies, in parallel.
1003- var wg sync.WaitGroup
1004- for _ , ipkg := range lpkg .Imports {
1005- imp := ld .pkgs [ipkg .ID ]
1006- wg .Add (1 )
1007- go func (imp * loaderPackage ) {
1008- ld .loadRecursive (imp )
1009- wg .Done ()
1010- }(imp )
1011- }
1012- wg .Wait ()
1013- ld .loadPackage (lpkg )
1014- })
1015- }
1016-
1017- // loadPackage loads the specified package.
1040+ // loadPackage loads/parses/typechecks the specified package.
10181041// It must be called only once per Package,
10191042// after immediate dependencies are loaded.
1020- // Precondition: ld.Mode & NeedTypes.
1043+ // Precondition: ld.Mode&(NeedSyntax| NeedTypes|NeedTypesInfo) != 0 .
10211044func (ld * loader ) loadPackage (lpkg * loaderPackage ) {
10221045 if lpkg .PkgPath == "unsafe" {
10231046 // Fill in the blanks to avoid surprises.
@@ -1053,6 +1076,10 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
10531076 if ! lpkg .needtypes && ! lpkg .needsrc {
10541077 return
10551078 }
1079+
1080+ // TODO(adonovan): this condition looks wrong:
1081+ // I think it should be lpkg.needtypes && !lpg.needsrc,
1082+ // so that NeedSyntax without NeedTypes can be satisfied by export data.
10561083 if ! lpkg .needsrc {
10571084 if err := ld .loadFromExportData (lpkg ); err != nil {
10581085 lpkg .Errors = append (lpkg .Errors , Error {
@@ -1169,15 +1196,19 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
11691196 return
11701197 }
11711198
1172- lpkg .TypesInfo = & types.Info {
1173- Types : make (map [ast.Expr ]types.TypeAndValue ),
1174- Defs : make (map [* ast.Ident ]types.Object ),
1175- Uses : make (map [* ast.Ident ]types.Object ),
1176- Implicits : make (map [ast.Node ]types.Object ),
1177- Instances : make (map [* ast.Ident ]types.Instance ),
1178- Scopes : make (map [ast.Node ]* types.Scope ),
1179- Selections : make (map [* ast.SelectorExpr ]* types.Selection ),
1180- FileVersions : make (map [* ast.File ]string ),
1199+ // Populate TypesInfo only if needed, as it
1200+ // causes the type checker to work much harder.
1201+ if ld .Config .Mode & NeedTypesInfo != 0 {
1202+ lpkg .TypesInfo = & types.Info {
1203+ Types : make (map [ast.Expr ]types.TypeAndValue ),
1204+ Defs : make (map [* ast.Ident ]types.Object ),
1205+ Uses : make (map [* ast.Ident ]types.Object ),
1206+ Implicits : make (map [ast.Node ]types.Object ),
1207+ Instances : make (map [* ast.Ident ]types.Instance ),
1208+ Scopes : make (map [ast.Node ]* types.Scope ),
1209+ Selections : make (map [* ast.SelectorExpr ]* types.Selection ),
1210+ FileVersions : make (map [* ast.File ]string ),
1211+ }
11811212 }
11821213 lpkg .TypesSizes = ld .sizes
11831214
@@ -1231,6 +1262,10 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
12311262 }
12321263 }
12331264
1265+ // Type-checking is CPU intensive.
1266+ cpuLimit <- unit {} // acquire a token
1267+ defer func () { <- cpuLimit }() // release a token
1268+
12341269 typErr := types .NewChecker (tc , ld .Fset , lpkg .Types , lpkg .TypesInfo ).Files (lpkg .Syntax )
12351270 lpkg .importErrors = nil // no longer needed
12361271
@@ -1295,8 +1330,11 @@ type importerFunc func(path string) (*types.Package, error)
12951330func (f importerFunc ) Import (path string ) (* types.Package , error ) { return f (path ) }
12961331
12971332// We use a counting semaphore to limit
1298- // the number of parallel I/O calls per process.
1299- var ioLimit = make (chan bool , 20 )
1333+ // the number of parallel I/O calls or CPU threads per process.
1334+ var (
1335+ ioLimit = make (chan unit , 20 )
1336+ cpuLimit = make (chan unit , runtime .GOMAXPROCS (0 ))
1337+ )
13001338
13011339func (ld * loader ) parseFile (filename string ) (* ast.File , error ) {
13021340 ld .parseCacheMu .Lock ()
@@ -1324,14 +1362,17 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) {
13241362 }
13251363 var err error
13261364 if src == nil {
1327- ioLimit <- true // acquire a token
1365+ ioLimit <- unit {} // acquire a token
13281366 src , err = os .ReadFile (filename )
13291367 <- ioLimit // release a token
13301368 }
13311369 if err != nil {
13321370 v .err = err
13331371 } else {
1372+ // Parsing is CPU intensive.
1373+ cpuLimit <- unit {} // acquire a token
13341374 v .f , v .err = ld .ParseFile (ld .Fset , filename , src )
1375+ <- cpuLimit // release a token
13351376 }
13361377
13371378 close (v .ready )
@@ -1531,4 +1572,4 @@ func usesExportData(cfg *Config) bool {
15311572 return cfg .Mode & NeedExportFile != 0 || cfg .Mode & NeedTypes != 0 && cfg .Mode & NeedDeps == 0
15321573}
15331574
1534- var _ interface {} = io . Discard // assert build toolchain is go1.16 or later
1575+ type unit struct {}
0 commit comments