@@ -398,12 +398,13 @@ func (p *Package) String() string { return p.ID }
398
398
// loaderPackage augments Package with state used during the loading phase
399
399
type loaderPackage struct {
400
400
* Package
401
- importErrors map [string ]error // maps each bad import to its error
402
- loadOnce sync.Once
403
- color uint8 // for cycle detection
404
- needsrc bool // load from source (Mode >= LoadTypes)
405
- needtypes bool // type information is either requested or depended on
406
- initial bool // package was matched by a pattern
401
+ importErrors map [string ]error // maps each bad import to its error
402
+ loadOnce sync.Once
403
+ color uint8 // for cycle detection
404
+ needsyntax bool // fill syntax trees
405
+ needtypes bool // basic type information is either requested or depended on (export data is enough)
406
+ needtypesinfo bool // full type information is either requested or depended on (need to load from source)
407
+ initial bool // package was matched by a pattern
407
408
}
408
409
409
410
// loader holds the working state of a single call to load.
@@ -415,7 +416,7 @@ type loader struct {
415
416
parseCacheMu sync.Mutex
416
417
exportMu sync.Mutex // enforces mutual exclusion of exportdata operations
417
418
418
- // Config.Mode contains the implied mode (see implyLoadMode ).
419
+ // Config.Mode contains the implied mode (see impliedLoadMode ).
419
420
// Implied mode contains all the fields we need the data for.
420
421
// In requestedMode there are the actually requested fields.
421
422
// We'll zero them out before returning packages to the user.
@@ -463,6 +464,10 @@ func newLoader(cfg *Config) *loader {
463
464
}
464
465
}
465
466
467
+ // Save the actually requested fields. We'll zero them out before returning packages to the user.
468
+ ld .requestedMode = ld .Mode
469
+ ld .Mode = impliedLoadMode (ld .Mode )
470
+
466
471
if ld .Mode & NeedTypes != 0 {
467
472
if ld .Fset == nil {
468
473
ld .Fset = token .NewFileSet ()
@@ -478,9 +483,6 @@ func newLoader(cfg *Config) *loader {
478
483
}
479
484
}
480
485
481
- // Save the actually requested fields. We'll zero them out before returning packages to the user.
482
- ld .requestedMode = ld .Mode
483
- ld .implyLoadMode ()
484
486
return ld
485
487
}
486
488
@@ -499,12 +501,26 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
499
501
if i , found := rootMap [pkg .ID ]; found {
500
502
rootIndex = i
501
503
}
504
+
505
+ // For root packages (rootIndex >= 0) load types if they were requested by NeedTypes.
506
+ // For all other packages (dependencies) load types only if types were requested (NeedTypes) for dependecies (NeedDeps).
507
+ explicitlyNeedTypes := ld .Mode & NeedTypes != 0 && (rootIndex >= 0 || ld .Mode & NeedDeps != 0 )
508
+
509
+ explicitlyNeedTypesInfo := ld .Mode & NeedTypesInfo != 0 && (rootIndex >= 0 || // load from source all root packages
510
+ ld .Mode & NeedDeps != 0 ) // load from source all dependencies if needed
511
+ hasValidExportData := (pkg .ExportFile != "" || pkg .PkgPath == "unsafe" ) &&
512
+ // overlays can invalidate export data. TODO(matloob): make this check fine-grained based on dependencies on overlaid files
513
+ len (ld .Overlay ) == 0
514
+ needTypesInfo := explicitlyNeedTypesInfo || (ld .Mode & NeedTypes != 0 && ! hasValidExportData )
515
+
516
+ explicitlyNeedSyntax := ld .Mode & NeedSyntax != 0 && (rootIndex >= 0 || ld .Mode & NeedDeps != 0 )
517
+ needSyntax := explicitlyNeedSyntax || needTypesInfo // types info loading requires syntax trees building
518
+
502
519
lpkg := & loaderPackage {
503
- Package : pkg ,
504
- needtypes : (ld .Mode & (NeedTypes | NeedTypesInfo ) != 0 && ld .Mode & NeedDeps != 0 && rootIndex < 0 ) || rootIndex >= 0 ,
505
- needsrc : (ld .Mode & (NeedSyntax | NeedTypesInfo ) != 0 && ld .Mode & NeedDeps != 0 && rootIndex < 0 ) || rootIndex >= 0 ||
506
- len (ld .Overlay ) > 0 || // Overlays can invalidate export data. TODO(matloob): make this check fine-grained based on dependencies on overlaid files
507
- pkg .ExportFile == "" && pkg .PkgPath != "unsafe" ,
520
+ Package : pkg ,
521
+ needtypes : explicitlyNeedTypes ,
522
+ needtypesinfo : needTypesInfo ,
523
+ needsyntax : needSyntax ,
508
524
}
509
525
ld .pkgs [lpkg .ID ] = lpkg
510
526
if rootIndex >= 0 {
@@ -518,6 +534,19 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
518
534
}
519
535
}
520
536
537
+ // Build loader packages for imported packages when no deeps are needed
538
+ if ld .Mode & NeedDeps == 0 {
539
+ for _ , pkg := range list {
540
+ for _ , ipkg := range pkg .Imports {
541
+ if imp := ld .pkgs [ipkg .ID ]; imp == nil {
542
+ ld .pkgs [ipkg .ID ] = & loaderPackage {
543
+ Package : ipkg ,
544
+ }
545
+ }
546
+ }
547
+ }
548
+ }
549
+
521
550
// Materialize the import graph.
522
551
523
552
const (
@@ -533,16 +562,16 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
533
562
// Invalid imports (cycles and missing nodes) are saved in the importErrors map.
534
563
// Thus, even in the presence of both kinds of errors, the Import graph remains a DAG.
535
564
//
536
- // visit returns whether the package needs src or has a transitive
565
+ // visit returns whether the package needs types info or has a transitive
537
566
// dependency on a package that does. These are the only packages
538
567
// for which we load source code.
539
568
var stack []* loaderPackage
540
569
var visit func (lpkg * loaderPackage ) bool
541
- var srcPkgs []* loaderPackage
570
+ var typesInfoPkgs []* loaderPackage
542
571
visit = func (lpkg * loaderPackage ) bool {
543
572
switch lpkg .color {
544
573
case black :
545
- return lpkg .needsrc
574
+ return lpkg .needtypesinfo
546
575
case grey :
547
576
panic ("internal error: grey node" )
548
577
}
@@ -569,22 +598,26 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
569
598
continue
570
599
}
571
600
572
- if visit (imp ) {
573
- lpkg .needsrc = true
601
+ // If don't need deps, just fill Imports for the root. No need to recurse further.
602
+ if loadsDeps (& ld .Config ) {
603
+ if visit (imp ) {
604
+ lpkg .needtypesinfo = true
605
+ lpkg .needsyntax = true // types info loading (needtypesinfo) requires syntax trees building
606
+ }
574
607
}
575
- lpkg .Imports [importPath ] = imp .Package
608
+ lpkg .Imports [importPath ] = imp .Package // deduplicate imported package
576
609
}
577
610
}
578
- if lpkg .needsrc {
579
- srcPkgs = append (srcPkgs , lpkg )
611
+ if lpkg .needtypesinfo {
612
+ typesInfoPkgs = append (typesInfoPkgs , lpkg )
580
613
}
581
614
if ld .Mode & NeedTypesSizes != 0 {
582
615
lpkg .TypesSizes = ld .sizes
583
616
}
584
617
stack = stack [:len (stack )- 1 ] // pop
585
618
lpkg .color = black
586
619
587
- return lpkg .needsrc
620
+ return lpkg .needtypesinfo
588
621
}
589
622
590
623
if ld .Mode & NeedImports == 0 {
@@ -598,16 +631,18 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
598
631
visit (lpkg )
599
632
}
600
633
}
601
- if ld .Mode & NeedImports != 0 && ld .Mode & NeedTypes != 0 {
602
- for _ , lpkg := range srcPkgs {
603
- // Complete type information is required for the
604
- // immediate dependencies of each source package.
605
- for _ , ipkg := range lpkg .Imports {
606
- imp := ld .pkgs [ipkg .ID ]
607
- imp .needtypes = true
608
- }
634
+
635
+ // Set needtypes for immediate dependencies if need types info
636
+ for _ , lpkg := range typesInfoPkgs {
637
+ // Complete type information is required for the
638
+ // immediate dependencies of packages for which
639
+ // we need types info.
640
+ for _ , ipkg := range lpkg .Imports {
641
+ imp := ld .pkgs [ipkg .ID ]
642
+ imp .needtypes = true
609
643
}
610
644
}
645
+
611
646
// Load type data if needed, starting at
612
647
// the initial packages (roots of the import DAG).
613
648
if ld .Mode & NeedTypes != 0 {
@@ -712,13 +747,6 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
712
747
// which would then require that such created packages be explicitly
713
748
// inserted back into the Import graph as a final step after export data loading.
714
749
// The Diamond test exercises this case.
715
- if ! lpkg .needtypes {
716
- return
717
- }
718
- if ! lpkg .needsrc {
719
- ld .loadFromExportData (lpkg )
720
- return // not a source package, don't get syntax trees
721
- }
722
750
723
751
appendError := func (err error ) {
724
752
// Convert various error types into the one true Error.
@@ -769,12 +797,35 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
769
797
lpkg .Errors = append (lpkg .Errors , errs ... )
770
798
}
771
799
772
- files , errs := ld .parseFiles (lpkg .CompiledGoFiles )
773
- for _ , err := range errs {
774
- appendError (err )
800
+ if lpkg .needsyntax {
801
+ files , errs := ld .parseFiles (lpkg .CompiledGoFiles )
802
+ for _ , err := range errs {
803
+ appendError (err )
804
+ }
805
+
806
+ lpkg .Syntax = files
807
+ } else if lpkg .needtypesinfo {
808
+ log .Fatalf ("Internal error: can't load package %s types info without loading syntax trees" , lpkg .ID )
775
809
}
776
810
777
- lpkg .Syntax = files
811
+ if ! lpkg .needtypesinfo {
812
+ if ! lpkg .needtypes {
813
+ // Need just syntax trees
814
+ return
815
+ }
816
+
817
+ _ , err := ld .loadFromExportData (lpkg )
818
+ if err == nil {
819
+ // Successfully types loaded from export data
820
+ return
821
+ }
822
+
823
+ log .Fatalf ("Failed to load package %s from export data: %s" , lpkg .ID , err )
824
+ }
825
+
826
+ if ! lpkg .needtypes {
827
+ log .Fatal ("Internal error: types will be loaded with types info" )
828
+ }
778
829
779
830
lpkg .TypesInfo = & types.Info {
780
831
Types : make (map [ast.Expr ]types.TypeAndValue ),
@@ -815,7 +866,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
815
866
tc := & types.Config {
816
867
Importer : importer ,
817
868
818
- // Type-check bodies of functions only in non- initial packages.
869
+ // Type-check bodies of functions only in initial packages.
819
870
// Example: for import graph A->B->C and initial packages {A,C},
820
871
// we can ignore function bodies in B.
821
872
IgnoreFuncBodies : ld .Mode & NeedDeps == 0 && ! lpkg .initial ,
@@ -1080,25 +1131,54 @@ func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error
1080
1131
return tpkg , nil
1081
1132
}
1082
1133
1083
- // implyLoadMode adds dependencies for choosed LoadMode in ld.Mode
1084
- func (ld * loader ) implyLoadMode () {
1085
- if ld .Mode & NeedTypesInfo != 0 && ld .Mode & NeedImports == 0 {
1086
- // If NeedTypesInfo, go/packages needs to do typechecking itself so it can
1087
- // associate type info with the AST. To do so, we need the export data
1088
- // for dependencies, which means we need to ask for the direct dependencies.
1089
- // NeedImports is used to ask for the direct dependencies.
1090
- ld .Mode |= NeedImports
1091
- ld .Logf ("Added load mode dependency of NeedTypesInfo: NeedImports" )
1134
+ func usesExportData (cfg * Config ) bool {
1135
+ return cfg .Mode & NeedExportsFile != 0 ||
1136
+ // If NeedTypes but not NeedTypesInfo we won't typecheck using sources, so we need export data.
1137
+ (cfg .Mode & NeedTypes != 0 && cfg .Mode & NeedTypesInfo == 0 ) ||
1138
+ // If NeedTypesInfo but not NeedDeps, we're typechecking a package using its sources plus its dependencies' export data
1139
+ (cfg .Mode & NeedTypesInfo != 0 && cfg .Mode & NeedDeps == 0 )
1140
+ }
1141
+
1142
+ func loadsDeps (cfg * Config ) bool {
1143
+ return cfg .Mode & NeedDeps != 0 ||
1144
+ // Immediate dependencies information (at least, export data) is required to do typechecking
1145
+ // on sources, which is required for the TypesInfo. In such cases we could load packages
1146
+ // without deps and then call go list again for immediate dependecies, but it's typically
1147
+ // much slower than running go list -deps=true once.
1148
+ cfg .Mode & NeedTypesInfo != 0
1149
+ }
1150
+
1151
+ // impliedLoadMode returns loadMode with it's dependencies
1152
+ func impliedLoadMode (loadMode LoadMode ) LoadMode {
1153
+ if loadMode & NeedTypesInfo != 0 && loadMode & NeedSyntax == 0 {
1154
+ // When NeedTypesInfo is set we load types info from source code.
1155
+ // For parsing the source code we need NeedSyntax.
1156
+ loadMode |= NeedSyntax
1157
+ }
1158
+
1159
+ if loadMode & NeedTypesInfo != 0 && loadMode & NeedImports == 0 {
1160
+ // When NeedTypesInfo is set we load types info from source code.
1161
+ // We need immediate dependencies types information for that.
1162
+ // NeedImports handles processing of immediate dependencies.
1163
+ loadMode |= NeedImports
1092
1164
}
1093
1165
1094
- if ld .Mode & NeedDeps != 0 && ld .Mode & NeedImports == 0 {
1166
+ if loadMode & NeedTypesInfo != 0 && loadMode & NeedTypes == 0 {
1167
+ // When NeedTypesInfo is set we load types info from source code,
1168
+ // this procedure also fills types.
1169
+ loadMode |= NeedTypes
1170
+ }
1171
+
1172
+ if loadMode & NeedTypesInfo != 0 && loadMode & NeedTypesSizes == 0 {
1173
+ // Types loading requires types sizes (set in types.Config).
1174
+ loadMode |= NeedTypesSizes
1175
+ }
1176
+
1177
+ if loadMode & NeedDeps != 0 && loadMode & NeedImports == 0 {
1095
1178
// With NeedDeps we need to load at least direct dependencies.
1096
1179
// NeedImports is used to ask for the direct dependencies.
1097
- ld .Mode |= NeedImports
1098
- ld .Logf ("Added load mode dependency of NeedDeps: NeedImports" )
1180
+ loadMode |= NeedImports
1099
1181
}
1100
- }
1101
1182
1102
- func usesExportData (cfg * Config ) bool {
1103
- return cfg .Mode & NeedExportsFile != 0 || cfg .Mode & NeedTypes != 0 && cfg .Mode & NeedDeps == 0
1183
+ return loadMode
1104
1184
}
0 commit comments