]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/go/internal/modload/modfile.go
[dev.cmdgo] all: merge master (9eee0ed) into dev.cmdgo
[gostls13.git] / src / cmd / go / internal / modload / modfile.go
1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package modload
6
7 import (
8         "context"
9         "errors"
10         "fmt"
11         "os"
12         "path/filepath"
13         "strings"
14         "sync"
15         "unicode"
16
17         "cmd/go/internal/base"
18         "cmd/go/internal/cfg"
19         "cmd/go/internal/fsys"
20         "cmd/go/internal/lockedfile"
21         "cmd/go/internal/modfetch"
22         "cmd/go/internal/par"
23         "cmd/go/internal/trace"
24
25         "golang.org/x/mod/modfile"
26         "golang.org/x/mod/module"
27         "golang.org/x/mod/semver"
28 )
29
30 const (
31         // narrowAllVersionV is the Go version (plus leading "v") at which the
32         // module-module "all" pattern no longer closes over the dependencies of
33         // tests outside of the main module.
34         narrowAllVersionV = "v1.16"
35
36         // lazyLoadingVersionV is the Go version (plus leading "v") at which a
37         // module's go.mod file is expected to list explicit requirements on every
38         // module that provides any package transitively imported by that module.
39         lazyLoadingVersionV = "v1.17"
40
41         // separateIndirectVersionV is the Go version (plus leading "v") at which
42         // "// indirect" dependencies are added in a block separate from the direct
43         // ones. See https://golang.org/issue/45965.
44         separateIndirectVersionV = "v1.17"
45 )
46
47 const (
48         // go117EnableLazyLoading toggles whether lazy-loading code paths should be
49         // active. It will be removed once the lazy loading implementation is stable
50         // and well-tested.
51         go117EnableLazyLoading = true
52
53         // go1117LazyTODO is a constant that exists only until lazy loading is
54         // implemented. Its use indicates a condition that will need to change if the
55         // main module is lazy.
56         go117LazyTODO = false
57 )
58
59 // modFileGoVersion returns the (non-empty) Go version at which the requirements
60 // in modFile are intepreted, or the latest Go version if modFile is nil.
61 func modFileGoVersion() string {
62         _ = TODOWorkspaces("this is obviously wrong.")
63         // Yes we're picking arbitrarily, we'll have to pass through the version
64         // we care about
65         modFile := MainModules.ModFile(MainModules.Versions()[0])
66         if modFile == nil {
67                 return LatestGoVersion()
68         }
69         if modFile.Go == nil || modFile.Go.Version == "" {
70                 // The main module necessarily has a go.mod file, and that file lacks a
71                 // 'go' directive. The 'go' command has been adding that directive
72                 // automatically since Go 1.12, so this module either dates to Go 1.11 or
73                 // has been erroneously hand-edited.
74                 //
75                 // The semantics of the go.mod file are more-or-less the same from Go 1.11
76                 // through Go 1.16, changing at 1.17 for lazy loading. So even though a
77                 // go.mod file without a 'go' directive is theoretically a Go 1.11 file,
78                 // scripts may assume that it ends up as a Go 1.16 module.
79                 return "1.16"
80         }
81         return modFile.Go.Version
82 }
83
84 // A modFileIndex is an index of data corresponding to a modFile
85 // at a specific point in time.
86 type modFileIndex struct {
87         data            []byte
88         dataNeedsFix    bool // true if fixVersion applied a change while parsing data
89         module          module.Version
90         goVersionV      string // GoVersion with "v" prefix
91         require         map[module.Version]requireMeta
92         replace         map[module.Version]module.Version
93         highestReplaced map[string]string // highest replaced version of each module path; empty string for wildcard-only replacements
94         exclude         map[module.Version]bool
95 }
96
97 type requireMeta struct {
98         indirect bool
99 }
100
101 // A modDepth indicates which dependencies should be loaded for a go.mod file.
102 type modDepth uint8
103
104 const (
105         lazy  modDepth = iota // load dependencies only as needed
106         eager                 // load all transitive dependencies eagerly
107 )
108
109 func modDepthFromGoVersion(goVersion string) modDepth {
110         if !go117EnableLazyLoading {
111                 return eager
112         }
113         if semver.Compare("v"+goVersion, lazyLoadingVersionV) < 0 {
114                 return eager
115         }
116         return lazy
117 }
118
119 // CheckAllowed returns an error equivalent to ErrDisallowed if m is excluded by
120 // the main module's go.mod or retracted by its author. Most version queries use
121 // this to filter out versions that should not be used.
122 func CheckAllowed(ctx context.Context, m module.Version) error {
123         if err := CheckExclusions(ctx, m); err != nil {
124                 return err
125         }
126         if err := CheckRetractions(ctx, m); err != nil {
127                 return err
128         }
129         return nil
130 }
131
132 // ErrDisallowed is returned by version predicates passed to Query and similar
133 // functions to indicate that a version should not be considered.
134 var ErrDisallowed = errors.New("disallowed module version")
135
136 // CheckExclusions returns an error equivalent to ErrDisallowed if module m is
137 // excluded by the main module's go.mod file.
138 func CheckExclusions(ctx context.Context, m module.Version) error {
139         for _, mainModule := range MainModules.Versions() {
140                 if index := MainModules.Index(mainModule); index != nil && index.exclude[m] {
141                         return module.VersionError(m, errExcluded)
142                 }
143         }
144         return nil
145 }
146
147 var errExcluded = &excludedError{}
148
149 type excludedError struct{}
150
151 func (e *excludedError) Error() string     { return "excluded by go.mod" }
152 func (e *excludedError) Is(err error) bool { return err == ErrDisallowed }
153
154 // CheckRetractions returns an error if module m has been retracted by
155 // its author.
156 func CheckRetractions(ctx context.Context, m module.Version) (err error) {
157         defer func() {
158                 if retractErr := (*ModuleRetractedError)(nil); err == nil || errors.As(err, &retractErr) {
159                         return
160                 }
161                 // Attribute the error to the version being checked, not the version from
162                 // which the retractions were to be loaded.
163                 if mErr := (*module.ModuleError)(nil); errors.As(err, &mErr) {
164                         err = mErr.Err
165                 }
166                 err = &retractionLoadingError{m: m, err: err}
167         }()
168
169         if m.Version == "" {
170                 // Main module, standard library, or file replacement module.
171                 // Cannot be retracted.
172                 return nil
173         }
174         if repl := Replacement(module.Version{Path: m.Path}); repl.Path != "" {
175                 // All versions of the module were replaced.
176                 // Don't load retractions, since we'd just load the replacement.
177                 return nil
178         }
179
180         // Find the latest available version of the module, and load its go.mod. If
181         // the latest version is replaced, we'll load the replacement.
182         //
183         // If there's an error loading the go.mod, we'll return it here. These errors
184         // should generally be ignored by callers since they happen frequently when
185         // we're offline. These errors are not equivalent to ErrDisallowed, so they
186         // may be distinguished from retraction errors.
187         //
188         // We load the raw file here: the go.mod file may have a different module
189         // path that we expect if the module or its repository was renamed.
190         // We still want to apply retractions to other aliases of the module.
191         rm, err := queryLatestVersionIgnoringRetractions(ctx, m.Path)
192         if err != nil {
193                 return err
194         }
195         summary, err := rawGoModSummary(rm)
196         if err != nil {
197                 return err
198         }
199
200         var rationale []string
201         isRetracted := false
202         for _, r := range summary.retract {
203                 if semver.Compare(r.Low, m.Version) <= 0 && semver.Compare(m.Version, r.High) <= 0 {
204                         isRetracted = true
205                         if r.Rationale != "" {
206                                 rationale = append(rationale, r.Rationale)
207                         }
208                 }
209         }
210         if isRetracted {
211                 return module.VersionError(m, &ModuleRetractedError{Rationale: rationale})
212         }
213         return nil
214 }
215
216 type ModuleRetractedError struct {
217         Rationale []string
218 }
219
220 func (e *ModuleRetractedError) Error() string {
221         msg := "retracted by module author"
222         if len(e.Rationale) > 0 {
223                 // This is meant to be a short error printed on a terminal, so just
224                 // print the first rationale.
225                 msg += ": " + ShortMessage(e.Rationale[0], "retracted by module author")
226         }
227         return msg
228 }
229
230 func (e *ModuleRetractedError) Is(err error) bool {
231         return err == ErrDisallowed
232 }
233
234 type retractionLoadingError struct {
235         m   module.Version
236         err error
237 }
238
239 func (e *retractionLoadingError) Error() string {
240         return fmt.Sprintf("loading module retractions for %v: %v", e.m, e.err)
241 }
242
243 func (e *retractionLoadingError) Unwrap() error {
244         return e.err
245 }
246
247 // ShortMessage returns a string from go.mod (for example, a retraction
248 // rationale or deprecation message) that is safe to print in a terminal.
249 //
250 // If the given string is empty, ShortMessage returns the given default. If the
251 // given string is too long or contains non-printable characters, ShortMessage
252 // returns a hard-coded string.
253 func ShortMessage(message, emptyDefault string) string {
254         const maxLen = 500
255         if i := strings.Index(message, "\n"); i >= 0 {
256                 message = message[:i]
257         }
258         message = strings.TrimSpace(message)
259         if message == "" {
260                 return emptyDefault
261         }
262         if len(message) > maxLen {
263                 return "(message omitted: too long)"
264         }
265         for _, r := range message {
266                 if !unicode.IsGraphic(r) && !unicode.IsSpace(r) {
267                         return "(message omitted: contains non-printable characters)"
268                 }
269         }
270         // NOTE: the go.mod parser rejects invalid UTF-8, so we don't check that here.
271         return message
272 }
273
274 // CheckDeprecation returns a deprecation message from the go.mod file of the
275 // latest version of the given module. Deprecation messages are comments
276 // before or on the same line as the module directives that start with
277 // "Deprecated:" and run until the end of the paragraph.
278 //
279 // CheckDeprecation returns an error if the message can't be loaded.
280 // CheckDeprecation returns "", nil if there is no deprecation message.
281 func CheckDeprecation(ctx context.Context, m module.Version) (deprecation string, err error) {
282         defer func() {
283                 if err != nil {
284                         err = fmt.Errorf("loading deprecation for %s: %w", m.Path, err)
285                 }
286         }()
287
288         if m.Version == "" {
289                 // Main module, standard library, or file replacement module.
290                 // Don't look up deprecation.
291                 return "", nil
292         }
293         if repl := Replacement(module.Version{Path: m.Path}); repl.Path != "" {
294                 // All versions of the module were replaced.
295                 // We'll look up deprecation separately for the replacement.
296                 return "", nil
297         }
298
299         latest, err := queryLatestVersionIgnoringRetractions(ctx, m.Path)
300         if err != nil {
301                 return "", err
302         }
303         summary, err := rawGoModSummary(latest)
304         if err != nil {
305                 return "", err
306         }
307         return summary.deprecated, nil
308 }
309
310 func replacement(mod module.Version, index *modFileIndex) (fromVersion string, to module.Version, ok bool) {
311         if r, ok := index.replace[mod]; ok {
312                 return mod.Version, r, true
313         }
314         if r, ok := index.replace[module.Version{Path: mod.Path}]; ok {
315                 return "", r, true
316         }
317         return "", module.Version{}, false
318 }
319
320 // Replacement returns the replacement for mod, if any, from go.mod.
321 // If there is no replacement for mod, Replacement returns
322 // a module.Version with Path == "".
323 func Replacement(mod module.Version) module.Version {
324         _ = TODOWorkspaces("support replaces in the go.work file")
325         foundFrom, found, foundModRoot := "", module.Version{}, ""
326         for _, v := range MainModules.Versions() {
327                 if index := MainModules.Index(v); index != nil {
328                         if from, r, ok := replacement(mod, index); ok {
329                                 modRoot := MainModules.ModRoot(v)
330                                 if foundModRoot != "" && foundFrom != from && found != r {
331                                         _ = TODOWorkspaces("once the go.work file supports replaces, recommend them as a way to override conflicts")
332                                         base.Errorf("conflicting replacements found for %v in workspace modules defined by %v and %v",
333                                                 mod, modFilePath(foundModRoot), modFilePath(modRoot))
334                                         return found
335                                 }
336                                 found, foundModRoot = r, modRoot
337                         }
338                 }
339         }
340         return found
341 }
342
343 // resolveReplacement returns the module actually used to load the source code
344 // for m: either m itself, or the replacement for m (iff m is replaced).
345 func resolveReplacement(m module.Version) module.Version {
346         if r := Replacement(m); r.Path != "" {
347                 return r
348         }
349         return m
350 }
351
352 // indexModFile rebuilds the index of modFile.
353 // If modFile has been changed since it was first read,
354 // modFile.Cleanup must be called before indexModFile.
355 func indexModFile(data []byte, modFile *modfile.File, mod module.Version, needsFix bool) *modFileIndex {
356         i := new(modFileIndex)
357         i.data = data
358         i.dataNeedsFix = needsFix
359
360         i.module = module.Version{}
361         if modFile.Module != nil {
362                 i.module = modFile.Module.Mod
363         }
364
365         i.goVersionV = ""
366         if modFile.Go == nil {
367                 rawGoVersion.Store(mod, "")
368         } else {
369                 // We're going to use the semver package to compare Go versions, so go ahead
370                 // and add the "v" prefix it expects once instead of every time.
371                 i.goVersionV = "v" + modFile.Go.Version
372                 rawGoVersion.Store(mod, modFile.Go.Version)
373         }
374
375         i.require = make(map[module.Version]requireMeta, len(modFile.Require))
376         for _, r := range modFile.Require {
377                 i.require[r.Mod] = requireMeta{indirect: r.Indirect}
378         }
379
380         i.replace = make(map[module.Version]module.Version, len(modFile.Replace))
381         for _, r := range modFile.Replace {
382                 if prev, dup := i.replace[r.Old]; dup && prev != r.New {
383                         base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v", r.Old, prev, r.New)
384                 }
385                 i.replace[r.Old] = r.New
386         }
387
388         i.highestReplaced = make(map[string]string)
389         for _, r := range modFile.Replace {
390                 v, ok := i.highestReplaced[r.Old.Path]
391                 if !ok || semver.Compare(r.Old.Version, v) > 0 {
392                         i.highestReplaced[r.Old.Path] = r.Old.Version
393                 }
394         }
395
396         i.exclude = make(map[module.Version]bool, len(modFile.Exclude))
397         for _, x := range modFile.Exclude {
398                 i.exclude[x.Mod] = true
399         }
400
401         return i
402 }
403
404 // modFileIsDirty reports whether the go.mod file differs meaningfully
405 // from what was indexed.
406 // If modFile has been changed (even cosmetically) since it was first read,
407 // modFile.Cleanup must be called before modFileIsDirty.
408 func (i *modFileIndex) modFileIsDirty(modFile *modfile.File) bool {
409         if i == nil {
410                 return modFile != nil
411         }
412
413         if i.dataNeedsFix {
414                 return true
415         }
416
417         if modFile.Module == nil {
418                 if i.module != (module.Version{}) {
419                         return true
420                 }
421         } else if modFile.Module.Mod != i.module {
422                 return true
423         }
424
425         if modFile.Go == nil {
426                 if i.goVersionV != "" {
427                         return true
428                 }
429         } else if "v"+modFile.Go.Version != i.goVersionV {
430                 if i.goVersionV == "" && cfg.BuildMod != "mod" {
431                         // go.mod files did not always require a 'go' version, so do not error out
432                         // if one is missing — we may be inside an older module in the module
433                         // cache, and should bias toward providing useful behavior.
434                 } else {
435                         return true
436                 }
437         }
438
439         if len(modFile.Require) != len(i.require) ||
440                 len(modFile.Replace) != len(i.replace) ||
441                 len(modFile.Exclude) != len(i.exclude) {
442                 return true
443         }
444
445         for _, r := range modFile.Require {
446                 if meta, ok := i.require[r.Mod]; !ok {
447                         return true
448                 } else if r.Indirect != meta.indirect {
449                         if cfg.BuildMod == "readonly" {
450                                 // The module's requirements are consistent; only the "// indirect"
451                                 // comments that are wrong. But those are only guaranteed to be accurate
452                                 // after a "go mod tidy" — it's a good idea to run those before
453                                 // committing a change, but it's certainly not mandatory.
454                         } else {
455                                 return true
456                         }
457                 }
458         }
459
460         for _, r := range modFile.Replace {
461                 if r.New != i.replace[r.Old] {
462                         return true
463                 }
464         }
465
466         for _, x := range modFile.Exclude {
467                 if !i.exclude[x.Mod] {
468                         return true
469                 }
470         }
471
472         return false
473 }
474
475 // rawGoVersion records the Go version parsed from each module's go.mod file.
476 //
477 // If a module is replaced, the version of the replacement is keyed by the
478 // replacement module.Version, not the version being replaced.
479 var rawGoVersion sync.Map // map[module.Version]string
480
481 // A modFileSummary is a summary of a go.mod file for which we do not need to
482 // retain complete information — for example, the go.mod file of a dependency
483 // module.
484 type modFileSummary struct {
485         module     module.Version
486         goVersion  string
487         depth      modDepth
488         require    []module.Version
489         retract    []retraction
490         deprecated string
491 }
492
493 // A retraction consists of a retracted version interval and rationale.
494 // retraction is like modfile.Retract, but it doesn't point to the syntax tree.
495 type retraction struct {
496         modfile.VersionInterval
497         Rationale string
498 }
499
500 // goModSummary returns a summary of the go.mod file for module m,
501 // taking into account any replacements for m, exclusions of its dependencies,
502 // and/or vendoring.
503 //
504 // m must be a version in the module graph, reachable from the Target module.
505 // In readonly mode, the go.sum file must contain an entry for m's go.mod file
506 // (or its replacement). goModSummary must not be called for the Target module
507 // itself, as its requirements may change. Use rawGoModSummary for other
508 // module versions.
509 //
510 // The caller must not modify the returned summary.
511 func goModSummary(m module.Version) (*modFileSummary, error) {
512         if m.Version == "" && MainModules.Contains(m.Path) {
513                 panic("internal error: goModSummary called on a main module")
514         }
515
516         if cfg.BuildMod == "vendor" {
517                 summary := &modFileSummary{
518                         module: module.Version{Path: m.Path},
519                 }
520                 if vendorVersion[m.Path] != m.Version {
521                         // This module is not vendored, so packages cannot be loaded from it and
522                         // it cannot be relevant to the build.
523                         return summary, nil
524                 }
525
526                 // For every module other than the target,
527                 // return the full list of modules from modules.txt.
528                 readVendorList()
529
530                 // We don't know what versions the vendored module actually relies on,
531                 // so assume that it requires everything.
532                 summary.require = vendorList
533                 return summary, nil
534         }
535
536         actual := resolveReplacement(m)
537         if HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() && actual.Version != "" {
538                 key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
539                 if !modfetch.HaveSum(key) {
540                         suggestion := fmt.Sprintf("; to add it:\n\tgo mod download %s", m.Path)
541                         return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion})
542                 }
543         }
544         summary, err := rawGoModSummary(actual)
545         if err != nil {
546                 return nil, err
547         }
548
549         if actual.Version == "" {
550                 // The actual module is a filesystem-local replacement, for which we have
551                 // unfortunately not enforced any sort of invariants about module lines or
552                 // matching module paths. Anything goes.
553                 //
554                 // TODO(bcmills): Remove this special-case, update tests, and add a
555                 // release note.
556         } else {
557                 if summary.module.Path == "" {
558                         return nil, module.VersionError(actual, errors.New("parsing go.mod: missing module line"))
559                 }
560
561                 // In theory we should only allow mpath to be unequal to m.Path here if the
562                 // version that we fetched lacks an explicit go.mod file: if the go.mod file
563                 // is explicit, then it should match exactly (to ensure that imports of other
564                 // packages within the module are interpreted correctly). Unfortunately, we
565                 // can't determine that information from the module proxy protocol: we'll have
566                 // to leave that validation for when we load actual packages from within the
567                 // module.
568                 if mpath := summary.module.Path; mpath != m.Path && mpath != actual.Path {
569                         return nil, module.VersionError(actual, fmt.Errorf(`parsing go.mod:
570         module declares its path as: %s
571                 but was required as: %s`, mpath, m.Path))
572                 }
573         }
574
575         for _, mainModule := range MainModules.Versions() {
576                 if index := MainModules.Index(mainModule); index != nil && len(index.exclude) > 0 {
577                         // Drop any requirements on excluded versions.
578                         // Don't modify the cached summary though, since we might need the raw
579                         // summary separately.
580                         haveExcludedReqs := false
581                         for _, r := range summary.require {
582                                 if index.exclude[r] {
583                                         haveExcludedReqs = true
584                                         break
585                                 }
586                         }
587                         if haveExcludedReqs {
588                                 s := new(modFileSummary)
589                                 *s = *summary
590                                 s.require = make([]module.Version, 0, len(summary.require))
591                                 for _, r := range summary.require {
592                                         if !index.exclude[r] {
593                                                 s.require = append(s.require, r)
594                                         }
595                                 }
596                                 summary = s
597                         }
598                 }
599         }
600         return summary, nil
601 }
602
603 // rawGoModSummary returns a new summary of the go.mod file for module m,
604 // ignoring all replacements that may apply to m and excludes that may apply to
605 // its dependencies.
606 //
607 // rawGoModSummary cannot be used on the Target module.
608 func rawGoModSummary(m module.Version) (*modFileSummary, error) {
609         if m.Path == "" && MainModules.Contains(m.Path) {
610                 panic("internal error: rawGoModSummary called on the Target module")
611         }
612
613         type cached struct {
614                 summary *modFileSummary
615                 err     error
616         }
617         c := rawGoModSummaryCache.Do(m, func() interface{} {
618                 summary := new(modFileSummary)
619                 name, data, err := rawGoModData(m)
620                 if err != nil {
621                         return cached{nil, err}
622                 }
623                 f, err := modfile.ParseLax(name, data, nil)
624                 if err != nil {
625                         return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(name), err))}
626                 }
627                 if f.Module != nil {
628                         summary.module = f.Module.Mod
629                         summary.deprecated = f.Module.Deprecated
630                 }
631                 if f.Go != nil && f.Go.Version != "" {
632                         rawGoVersion.LoadOrStore(m, f.Go.Version)
633                         summary.goVersion = f.Go.Version
634                         summary.depth = modDepthFromGoVersion(f.Go.Version)
635                 } else {
636                         summary.depth = eager
637                 }
638                 if len(f.Require) > 0 {
639                         summary.require = make([]module.Version, 0, len(f.Require))
640                         for _, req := range f.Require {
641                                 summary.require = append(summary.require, req.Mod)
642                         }
643                 }
644                 if len(f.Retract) > 0 {
645                         summary.retract = make([]retraction, 0, len(f.Retract))
646                         for _, ret := range f.Retract {
647                                 summary.retract = append(summary.retract, retraction{
648                                         VersionInterval: ret.VersionInterval,
649                                         Rationale:       ret.Rationale,
650                                 })
651                         }
652                 }
653
654                 return cached{summary, nil}
655         }).(cached)
656
657         return c.summary, c.err
658 }
659
660 var rawGoModSummaryCache par.Cache // module.Version → rawGoModSummary result
661
662 // rawGoModData returns the content of the go.mod file for module m, ignoring
663 // all replacements that may apply to m.
664 //
665 // rawGoModData cannot be used on the Target module.
666 //
667 // Unlike rawGoModSummary, rawGoModData does not cache its results in memory.
668 // Use rawGoModSummary instead unless you specifically need these bytes.
669 func rawGoModData(m module.Version) (name string, data []byte, err error) {
670         if m.Version == "" {
671                 // m is a replacement module with only a file path.
672                 dir := m.Path
673                 if !filepath.IsAbs(dir) {
674                         dir = filepath.Join(ModRoot(), dir)
675                 }
676                 name = filepath.Join(dir, "go.mod")
677                 if gomodActual, ok := fsys.OverlayPath(name); ok {
678                         // Don't lock go.mod if it's part of the overlay.
679                         // On Plan 9, locking requires chmod, and we don't want to modify any file
680                         // in the overlay. See #44700.
681                         data, err = os.ReadFile(gomodActual)
682                 } else {
683                         data, err = lockedfile.Read(gomodActual)
684                 }
685                 if err != nil {
686                         return "", nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(name), err))
687                 }
688         } else {
689                 if !semver.IsValid(m.Version) {
690                         // Disallow the broader queries supported by fetch.Lookup.
691                         base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version)
692                 }
693                 name = "go.mod"
694                 data, err = modfetch.GoMod(m.Path, m.Version)
695         }
696         return name, data, err
697 }
698
699 // queryLatestVersionIgnoringRetractions looks up the latest version of the
700 // module with the given path without considering retracted or excluded
701 // versions.
702 //
703 // If all versions of the module are replaced,
704 // queryLatestVersionIgnoringRetractions returns the replacement without making
705 // a query.
706 //
707 // If the queried latest version is replaced,
708 // queryLatestVersionIgnoringRetractions returns the replacement.
709 func queryLatestVersionIgnoringRetractions(ctx context.Context, path string) (latest module.Version, err error) {
710         type entry struct {
711                 latest module.Version
712                 err    error
713         }
714         e := latestVersionIgnoringRetractionsCache.Do(path, func() interface{} {
715                 ctx, span := trace.StartSpan(ctx, "queryLatestVersionIgnoringRetractions "+path)
716                 defer span.Done()
717
718                 if repl := Replacement(module.Version{Path: path}); repl.Path != "" {
719                         // All versions of the module were replaced.
720                         // No need to query.
721                         return &entry{latest: repl}
722                 }
723
724                 // Find the latest version of the module.
725                 // Ignore exclusions from the main module's go.mod.
726                 const ignoreSelected = ""
727                 var allowAll AllowedFunc
728                 rev, err := Query(ctx, path, "latest", ignoreSelected, allowAll)
729                 if err != nil {
730                         return &entry{err: err}
731                 }
732                 latest := module.Version{Path: path, Version: rev.Version}
733                 if repl := resolveReplacement(latest); repl.Path != "" {
734                         latest = repl
735                 }
736                 return &entry{latest: latest}
737         }).(*entry)
738         return e.latest, e.err
739 }
740
741 var latestVersionIgnoringRetractionsCache par.Cache // path → queryLatestVersionIgnoringRetractions result