From c445a61e5256914510f201d5bda5e526249217d6 Mon Sep 17 00:00:00 2001 From: Ian Alexander Date: Thu, 2 Oct 2025 16:56:19 -0400 Subject: [PATCH] cmd/go: add loaderstate as field on `QueryMatchesMainModulesError` This change modifies the type `QueryMatchesMainModulesError` to have an additional field to store the current module loader state. The field is used to break the dependency on the global `modload.LoaderState` variable. This commit is part of the overall effort to eliminate global modloader state. Change-Id: Ia2066fab9f3ec4ffdd3d7393dacdf65c0fd35b92 Reviewed-on: https://go-review.googlesource.com/c/go/+/711118 LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase Reviewed-by: Michael Matloob --- src/cmd/go/internal/modget/get.go | 16 ++++++++------- src/cmd/go/internal/modload/query.go | 29 ++++++++++++++++------------ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 466669f36e..f9522860fa 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -683,7 +683,7 @@ func (r *resolver) queryPattern(loaderstate *modload.State, ctx context.Context, // checkAllowedOr is like modload.CheckAllowed, but it always allows the requested // and current versions (even if they are retracted or otherwise excluded). -func (r *resolver) checkAllowedOr(loaderstate *modload.State, requested string, selected func(string) string) modload.AllowedFunc { +func (r *resolver) checkAllowedOr(s *modload.State, requested string, selected func(string) string) modload.AllowedFunc { return func(ctx context.Context, m module.Version) error { if m.Version == requested { return modload.CheckExclusions(ctx, m) @@ -734,7 +734,7 @@ func (r *resolver) queryNone(loaderstate *modload.State, ctx context.Context, q // However, neither of those behaviors would be consistent with the // plain meaning of the query. To try to reduce confusion, reject the // query explicitly. - return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{v}, Pattern: q.pattern, Query: q.version}) + return errSet(&modload.QueryMatchesMainModulesError{LoaderState: loaderstate, MainModules: []module.Version{v}, Pattern: q.pattern, Query: q.version}) } return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}} @@ -747,7 +747,7 @@ func (r *resolver) queryNone(loaderstate *modload.State, ctx context.Context, q } q.pathOnce(curM.Path, func() pathSet { if modload.HasModRoot(loaderstate) && curM.Version == "" && loaderstate.MainModules.Contains(curM.Path) { - return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version}) + return errSet(&modload.QueryMatchesMainModulesError{LoaderState: loaderstate, MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version}) } return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}} }) @@ -851,6 +851,7 @@ func (r *resolver) queryWildcard(loaderstate *modload.State, ctx context.Context if loaderstate.MainModules.Contains(curM.Path) && !versionOkForMainModule(q.version) { if q.matchesPath(curM.Path) { return errSet(&modload.QueryMatchesMainModulesError{ + LoaderState: loaderstate, MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version, @@ -1482,7 +1483,7 @@ func (r *resolver) applyUpgrades(loaderstate *modload.State, ctx context.Context // In the vast majority of cases, we expect only one module per pathSet, // but we want to give some minimal additional tools so that users can add an // extra argument or two on the command line to resolve simple ambiguities. -func (r *resolver) disambiguate(loaderstate *modload.State, cs pathSet) (filtered pathSet, isPackage bool, m module.Version, unique bool) { +func (r *resolver) disambiguate(s *modload.State, cs pathSet) (filtered pathSet, isPackage bool, m module.Version, unique bool) { if len(cs.pkgMods) == 0 && cs.mod.Path == "" { panic("internal error: resolveIfUnambiguous called with empty pathSet") } @@ -1494,7 +1495,7 @@ func (r *resolver) disambiguate(loaderstate *modload.State, cs pathSet) (filtere continue } - if loaderstate.MainModules.Contains(m.Path) { + if s.MainModules.Contains(m.Path) { if m.Version == "" { return pathSet{}, true, m, true } @@ -1944,13 +1945,14 @@ func (r *resolver) reportChanges(oldReqs, newReqs []module.Version) { // resolve records that module m must be at its indicated version (which may be // "none") due to query q. If some other query forces module m to be at a // different version, resolve reports a conflict error. -func (r *resolver) resolve(loaderstate *modload.State, q *query, m module.Version) { +func (r *resolver) resolve(s *modload.State, q *query, m module.Version) { if m.Path == "" { panic("internal error: resolving a module.Version with an empty path") } - if loaderstate.MainModules.Contains(m.Path) && m.Version != "" { + if s.MainModules.Contains(m.Path) && m.Version != "" { reportError(q, &modload.QueryMatchesMainModulesError{ + LoaderState: s, MainModules: []module.Version{{Path: m.Path}}, Pattern: q.pattern, Query: q.version, diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index 17a0aef21a..2bf3fcb846 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -763,6 +763,7 @@ func QueryPattern(loaderstate *State, ctx context.Context, pattern, query string return nil, modOnly, nil } else if len(mainModuleMatches) != 0 { return nil, nil, &QueryMatchesMainModulesError{ + LoaderState: loaderstate, MainModules: mainModuleMatches, Pattern: pattern, Query: query, @@ -826,8 +827,9 @@ func QueryPattern(loaderstate *State, ctx context.Context, pattern, query string if len(mainModuleMatches) > 0 && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) { return nil, nil, &QueryMatchesMainModulesError{ - Pattern: pattern, - Query: query, + LoaderState: loaderstate, + Pattern: pattern, + Query: query, } } return slices.Clip(results), modOnly, err @@ -1112,7 +1114,7 @@ type versionRepo interface { CheckReuse(context.Context, *codehost.Origin) error Versions(ctx context.Context, prefix string) (*modfetch.Versions, error) Stat(ctx context.Context, rev string) (*modfetch.RevInfo, error) - Latest(context.Context) (*modfetch.RevInfo, error) + Latest(ctx context.Context) (*modfetch.RevInfo, error) } var _ versionRepo = modfetch.Repo(nil) @@ -1130,7 +1132,7 @@ func lookupRepo(loaderstate *State, ctx context.Context, proxy, path string) (re if loaderstate.MainModules == nil { return repo, err } else if _, ok := loaderstate.MainModules.HighestReplaced()[path]; ok { - return &replacementRepo{repo: repo}, nil + return &replacementRepo{repo: repo, loaderstate: loaderstate}, nil } return repo, err @@ -1163,7 +1165,8 @@ func (er emptyRepo) Latest(ctx context.Context) (*modfetch.RevInfo, error) { ret // modules, so a replacementRepo should only be constructed for a module that // actually has one or more valid replacements. type replacementRepo struct { - repo versionRepo + repo versionRepo + loaderstate *State } var _ versionRepo = (*replacementRepo)(nil) @@ -1186,8 +1189,8 @@ func (rr *replacementRepo) Versions(ctx context.Context, prefix string) (*modfet } versions := repoVersions.List - for _, mm := range LoaderState.MainModules.Versions() { - if index := LoaderState.MainModules.Index(mm); index != nil && len(index.replace) > 0 { + for _, mm := range rr.loaderstate.MainModules.Versions() { + if index := rr.loaderstate.MainModules.Index(mm); index != nil && len(index.replace) > 0 { path := rr.ModulePath() for m := range index.replace { if m.Path == path && strings.HasPrefix(m.Version, prefix) && m.Version != "" && !module.IsPseudoVersion(m.Version) { @@ -1215,8 +1218,8 @@ func (rr *replacementRepo) Stat(ctx context.Context, rev string) (*modfetch.RevI return info, err } var hasReplacements bool - for _, v := range LoaderState.MainModules.Versions() { - if index := LoaderState.MainModules.Index(v); index != nil && len(index.replace) > 0 { + for _, v := range rr.loaderstate.MainModules.Versions() { + if index := rr.loaderstate.MainModules.Index(v); index != nil && len(index.replace) > 0 { hasReplacements = true } } @@ -1239,7 +1242,7 @@ func (rr *replacementRepo) Stat(ctx context.Context, rev string) (*modfetch.RevI } } - if r := Replacement(LoaderState, module.Version{Path: path, Version: v}); r.Path == "" { + if r := Replacement(rr.loaderstate, module.Version{Path: path, Version: v}); r.Path == "" { return info, err } return rr.replacementStat(v) @@ -1249,7 +1252,7 @@ func (rr *replacementRepo) Latest(ctx context.Context) (*modfetch.RevInfo, error info, err := rr.repo.Latest(ctx) path := rr.ModulePath() - if v, ok := LoaderState.MainModules.HighestReplaced()[path]; ok { + if v, ok := rr.loaderstate.MainModules.HighestReplaced()[path]; ok { if v == "" { // The only replacement is a wildcard that doesn't specify a version, so // synthesize a pseudo-version with an appropriate major version and a @@ -1284,13 +1287,15 @@ func (rr *replacementRepo) replacementStat(v string) (*modfetch.RevInfo, error) // a version of the main module that cannot be satisfied. // (The main module's version cannot be changed.) type QueryMatchesMainModulesError struct { + LoaderState *State MainModules []module.Version Pattern string Query string } func (e *QueryMatchesMainModulesError) Error() string { - if LoaderState.MainModules.Contains(e.Pattern) { + // TODO(jitsu): break dependency on loaderstate + if e.LoaderState.MainModules.Contains(e.Pattern) { return fmt.Sprintf("can't request version %q of the main module (%s)", e.Query, e.Pattern) } -- 2.52.0