@@ -22,24 +22,6 @@ import (
22
22
errors "golang.org/x/xerrors"
23
23
)
24
24
25
- type importer struct {
26
- snapshot * snapshot
27
- ctx context.Context
28
-
29
- // seen maintains the set of previously imported packages.
30
- // If we have seen a package that is already in this map, we have a circular import.
31
- seen map [packageID ]struct {}
32
-
33
- // topLevelPackageID is the ID of the package from which type-checking began.
34
- topLevelPackageID packageID
35
-
36
- // parentPkg is the package that imports the current package.
37
- parentPkg * pkg
38
-
39
- // parentCheckPackageHandle is the check package handle that imports the current package.
40
- parentCheckPackageHandle * checkPackageHandle
41
- }
42
-
43
25
// checkPackageHandle implements source.CheckPackageHandle.
44
26
type checkPackageHandle struct {
45
27
handle * memoize.Handle
@@ -76,41 +58,47 @@ type checkPackageData struct {
76
58
}
77
59
78
60
// checkPackageHandle returns a source.CheckPackageHandle for a given package and config.
79
- func (imp * importer ) checkPackageHandle (ctx context.Context , id packageID ) (* checkPackageHandle , error ) {
80
- // Determine the mode that the files should be parsed in.
81
- mode := imp .mode (id )
82
-
61
+ func (s * snapshot ) checkPackageHandle (ctx context.Context , id packageID , mode source.ParseMode ) (* checkPackageHandle , error ) {
83
62
// Check if we already have this CheckPackageHandle cached.
84
- if cph := imp . snapshot .getPackage (id , mode ); cph != nil {
63
+ if cph := s .getPackage (id , mode ); cph != nil {
85
64
return cph , nil
86
65
}
87
66
88
67
// Build the CheckPackageHandle for this ID and its dependencies.
89
- cph , err := imp .buildKey (ctx , id , mode )
68
+ cph , err := s .buildKey (ctx , id , mode )
90
69
if err != nil {
91
70
return nil , err
92
71
}
93
-
94
- h := imp .snapshot .view .session .cache .store .Bind (string (cph .key ), func (ctx context.Context ) interface {} {
72
+ h := s .view .session .cache .store .Bind (string (cph .key ), func (ctx context.Context ) interface {} {
73
+ // Begin loading the direct dependencies, in parallel.
74
+ for _ , impID := range cph .imports {
75
+ dep := s .getPackage (impID , source .ParseExported )
76
+ if dep == nil {
77
+ continue
78
+ }
79
+ go func (dep * checkPackageHandle ) {
80
+ dep .check (ctx )
81
+ }(dep )
82
+ }
95
83
data := & checkPackageData {}
96
- data .pkg , data .err = imp .typeCheck (ctx , cph )
84
+ data .pkg , data .err = s .typeCheck (ctx , cph )
97
85
return data
98
86
})
99
87
cph .handle = h
100
88
101
89
// Cache the CheckPackageHandle in the snapshot.
102
- imp . snapshot .addPackage (cph )
90
+ s .addPackage (cph )
103
91
104
92
return cph , nil
105
93
}
106
94
107
95
// buildKey computes the checkPackageKey for a given checkPackageHandle.
108
- func (imp * importer ) buildKey (ctx context.Context , id packageID , mode source.ParseMode ) (* checkPackageHandle , error ) {
109
- m := imp . snapshot .getMetadata (id )
96
+ func (s * snapshot ) buildKey (ctx context.Context , id packageID , mode source.ParseMode ) (* checkPackageHandle , error ) {
97
+ m := s .getMetadata (id )
110
98
if m == nil {
111
99
return nil , errors .Errorf ("no metadata for %s" , id )
112
100
}
113
- phs , err := imp .parseGoHandles (ctx , m , mode )
101
+ phs , err := s .parseGoHandles (ctx , m , mode )
114
102
if err != nil {
115
103
return nil , err
116
104
}
@@ -127,17 +115,12 @@ func (imp *importer) buildKey(ctx context.Context, id packageID, mode source.Par
127
115
return deps [i ] < deps [j ]
128
116
})
129
117
130
- // Create the dep importer for use on the dependency handles.
131
- depImporter := & importer {
132
- snapshot : imp .snapshot ,
133
- topLevelPackageID : imp .topLevelPackageID ,
134
- }
135
118
// Begin computing the key by getting the depKeys for all dependencies.
136
119
var depKeys [][]byte
137
- for _ , dep := range deps {
138
- depHandle , err := depImporter .checkPackageHandle (ctx , dep )
120
+ for _ , depID := range deps {
121
+ depHandle , err := s .checkPackageHandle (ctx , depID , source . ParseExported )
139
122
if err != nil {
140
- log .Error (ctx , "no dep handle" , err , telemetry .Package .Of (dep ))
123
+ log .Error (ctx , "no dep handle" , err , telemetry .Package .Of (depID ))
141
124
142
125
// One bad dependency should not prevent us from checking the entire package.
143
126
// Add a special key to mark a bad dependency.
@@ -215,52 +198,20 @@ func (cph *checkPackageHandle) cached() (*pkg, error) {
215
198
return data .pkg , data .err
216
199
}
217
200
218
- func (imp * importer ) parseGoHandles (ctx context.Context , m * metadata , mode source.ParseMode ) ([]source.ParseGoHandle , error ) {
201
+ func (s * snapshot ) parseGoHandles (ctx context.Context , m * metadata , mode source.ParseMode ) ([]source.ParseGoHandle , error ) {
219
202
phs := make ([]source.ParseGoHandle , 0 , len (m .files ))
220
203
for _ , uri := range m .files {
221
- f , err := imp . snapshot .view .GetFile (ctx , uri )
204
+ f , err := s .view .GetFile (ctx , uri )
222
205
if err != nil {
223
206
return nil , err
224
207
}
225
- fh := imp . snapshot .Handle (ctx , f )
226
- phs = append (phs , imp . snapshot .view .session .cache .ParseGoHandle (fh , mode ))
208
+ fh := s .Handle (ctx , f )
209
+ phs = append (phs , s .view .session .cache .ParseGoHandle (fh , mode ))
227
210
}
228
211
return phs , nil
229
212
}
230
213
231
- func (imp * importer ) mode (id packageID ) source.ParseMode {
232
- if imp .topLevelPackageID == id {
233
- return source .ParseFull
234
- }
235
- return source .ParseExported
236
- }
237
-
238
- func (imp * importer ) Import (pkgPath string ) (* types.Package , error ) {
239
- ctx , done := trace .StartSpan (imp .ctx , "cache.importer.Import" , telemetry .PackagePath .Of (pkgPath ))
240
- defer done ()
241
-
242
- // We need to set the parent package's imports, so there should always be one.
243
- if imp .parentPkg == nil {
244
- return nil , errors .Errorf ("no parent package for import %s" , pkgPath )
245
- }
246
- // Get the CheckPackageHandle from the importing package.
247
- id , ok := imp .parentCheckPackageHandle .imports [packagePath (pkgPath )]
248
- if ! ok {
249
- return nil , errors .Errorf ("no package data for import path %s" , pkgPath )
250
- }
251
- cph := imp .snapshot .getPackage (id , source .ParseExported )
252
- if cph == nil {
253
- return nil , errors .Errorf ("no cached package for %s" , id )
254
- }
255
- pkg , err := cph .check (ctx )
256
- if err != nil {
257
- return nil , err
258
- }
259
- imp .parentPkg .imports [packagePath (pkgPath )] = pkg
260
- return pkg .GetTypes (), nil
261
- }
262
-
263
- func (imp * importer ) typeCheck (ctx context.Context , cph * checkPackageHandle ) (* pkg , error ) {
214
+ func (s * snapshot ) typeCheck (ctx context.Context , cph * checkPackageHandle ) (* pkg , error ) {
264
215
ctx , done := trace .StartSpan (ctx , "cache.importer.typeCheck" , telemetry .Package .Of (cph .m .id ))
265
216
defer done ()
266
217
@@ -270,7 +221,7 @@ func (imp *importer) typeCheck(ctx context.Context, cph *checkPackageHandle) (*p
270
221
}
271
222
272
223
pkg := & pkg {
273
- view : imp . snapshot .view ,
224
+ view : s .view ,
274
225
id : cph .m .id ,
275
226
mode : cph .mode ,
276
227
pkgPath : cph .m .pkgPath ,
@@ -329,9 +280,24 @@ func (imp *importer) typeCheck(ctx context.Context, cph *checkPackageHandle) (*p
329
280
Error : func (e error ) {
330
281
rawErrors = append (rawErrors , e )
331
282
},
332
- Importer : imp .depImporter (ctx , cph , pkg ),
283
+ Importer : importerFunc (func (pkgPath string ) (* types.Package , error ) {
284
+ impID , ok := cph .imports [packagePath (pkgPath )]
285
+ if ! ok {
286
+ return nil , errors .Errorf ("no package data for import %s" , pkgPath )
287
+ }
288
+ dep := s .getPackage (impID , source .ParseExported )
289
+ if dep == nil {
290
+ return nil , errors .Errorf ("no package for import %s" , impID )
291
+ }
292
+ depPkg , err := dep .check (ctx )
293
+ if err != nil {
294
+ return nil , err
295
+ }
296
+ pkg .imports [depPkg .pkgPath ] = depPkg
297
+ return depPkg .types , nil
298
+ }),
333
299
}
334
- check := types .NewChecker (cfg , imp . snapshot .view .session .cache .FileSet (), pkg .types , pkg .typesInfo )
300
+ check := types .NewChecker (cfg , s .view .session .cache .FileSet (), pkg .types , pkg .typesInfo )
335
301
336
302
// Type checking errors are handled via the config, so ignore them here.
337
303
_ = check .Files (files )
@@ -350,19 +316,8 @@ func (imp *importer) typeCheck(ctx context.Context, cph *checkPackageHandle) (*p
350
316
return pkg , nil
351
317
}
352
318
353
- func (imp * importer ) depImporter (ctx context.Context , cph * checkPackageHandle , pkg * pkg ) * importer {
354
- // Handle circular imports by copying previously seen imports.
355
- seen := make (map [packageID ]struct {})
356
- for k , v := range imp .seen {
357
- seen [k ] = v
358
- }
359
- seen [pkg .id ] = struct {}{}
360
- return & importer {
361
- snapshot : imp .snapshot ,
362
- topLevelPackageID : imp .topLevelPackageID ,
363
- parentPkg : pkg ,
364
- parentCheckPackageHandle : cph ,
365
- seen : seen ,
366
- ctx : ctx ,
367
- }
368
- }
319
+ // An importFunc is an implementation of the single-method
320
+ // types.Importer interface based on a function value.
321
+ type importerFunc func (path string ) (* types.Package , error )
322
+
323
+ func (f importerFunc ) Import (path string ) (* types.Package , error ) { return f (path ) }
0 commit comments