Skip to content

Commit

Permalink
internal/persistent: use generics
Browse files Browse the repository at this point in the history
Now that we're on 1.18+, make internal/persistent.Map generic.

Change-Id: I3403241fe22e28f969d7feb09a752b52f0d2ee4d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/524759
gopls-CI: kokoro <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Alan Donovan <[email protected]>
  • Loading branch information
findleyr committed Sep 1, 2023
1 parent a1a928d commit 010e045
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 121 deletions.
9 changes: 4 additions & 5 deletions gopls/internal/lsp/cache/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,7 @@ func (s *snapshot) getPackageHandles(ctx context.Context, ids []PackageID) (map[
unfinishedSuccs: int32(len(m.DepsByPkgPath)),
}
if entry, hit := b.s.packages.Get(m.ID); hit {
n.ph = entry.(*packageHandle)
n.ph = entry
}
if n.unfinishedSuccs == 0 {
leaves = append(leaves, n)
Expand Down Expand Up @@ -1118,12 +1118,11 @@ func (b *packageHandleBuilder) buildPackageHandle(ctx context.Context, n *handle
}

// Check the packages map again in case another goroutine got there first.
if alt, ok := b.s.packages.Get(n.m.ID); ok && alt.(*packageHandle).validated {
altPH := alt.(*packageHandle)
if altPH.m != n.m {
if alt, ok := b.s.packages.Get(n.m.ID); ok && alt.validated {
if alt.m != n.m {
bug.Reportf("existing package handle does not match for %s", n.m.ID)
}
n.ph = altPH
n.ph = alt
} else {
b.s.packages.Set(n.m.ID, n.ph, nil)
}
Expand Down
3 changes: 1 addition & 2 deletions gopls/internal/lsp/cache/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,7 @@ func (s *snapshot) load(ctx context.Context, allowNetwork bool, scopes ...loadSc
s.mu.Lock()

// Assert the invariant s.packages.Get(id).m == s.meta.metadata[id].
s.packages.Range(func(k, v interface{}) {
id, ph := k.(PackageID), v.(*packageHandle)
s.packages.Range(func(id PackageID, ph *packageHandle) {
if s.meta.metadata[id] != ph.m {
panic("inconsistent metadata")
}
Expand Down
31 changes: 8 additions & 23 deletions gopls/internal/lsp/cache/maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,14 @@ import (
"golang.org/x/tools/internal/persistent"
)

// TODO(euroelessar): Use generics once support for go1.17 is dropped.

type filesMap struct {
impl *persistent.Map
impl *persistent.Map[span.URI, source.FileHandle]
overlayMap map[span.URI]*Overlay // the subset that are overlays
}

// uriLessInterface is the < relation for "any" values containing span.URIs.
func uriLessInterface(a, b interface{}) bool {
return a.(span.URI) < b.(span.URI)
}

func newFilesMap() filesMap {
return filesMap{
impl: persistent.NewMap(uriLessInterface),
impl: new(persistent.Map[span.URI, source.FileHandle]),
overlayMap: make(map[span.URI]*Overlay),
}
}
Expand Down Expand Up @@ -53,9 +46,7 @@ func (m filesMap) Get(key span.URI) (source.FileHandle, bool) {
}

func (m filesMap) Range(do func(key span.URI, value source.FileHandle)) {
m.impl.Range(func(key, value interface{}) {
do(key.(span.URI), value.(source.FileHandle))
})
m.impl.Range(do)
}

func (m filesMap) Set(key span.URI, value source.FileHandle) {
Expand Down Expand Up @@ -86,19 +77,13 @@ func (m filesMap) overlays() []*Overlay {
return overlays
}

func packageIDLessInterface(x, y interface{}) bool {
return x.(PackageID) < y.(PackageID)
}

type knownDirsSet struct {
impl *persistent.Map
impl *persistent.Map[span.URI, struct{}]
}

func newKnownDirsSet() knownDirsSet {
return knownDirsSet{
impl: persistent.NewMap(func(a, b interface{}) bool {
return a.(span.URI) < b.(span.URI)
}),
impl: new(persistent.Map[span.URI, struct{}]),
}
}

Expand All @@ -118,8 +103,8 @@ func (s knownDirsSet) Contains(key span.URI) bool {
}

func (s knownDirsSet) Range(do func(key span.URI)) {
s.impl.Range(func(key, value interface{}) {
do(key.(span.URI))
s.impl.Range(func(key span.URI, value struct{}) {
do(key)
})
}

Expand All @@ -128,7 +113,7 @@ func (s knownDirsSet) SetAll(other knownDirsSet) {
}

func (s knownDirsSet) Insert(key span.URI) {
s.impl.Set(key, nil, nil)
s.impl.Set(key, struct{}{}, nil)
}

func (s knownDirsSet) Remove(key span.URI) {
Expand Down
6 changes: 3 additions & 3 deletions gopls/internal/lsp/cache/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (s *snapshot) ParseMod(ctx context.Context, fh source.FileHandle) (*source.
}

// Await result.
v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
v, err := s.awaitPromise(ctx, entry)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -130,7 +130,7 @@ func (s *snapshot) ParseWork(ctx context.Context, fh source.FileHandle) (*source
}

// Await result.
v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
v, err := s.awaitPromise(ctx, entry)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -240,7 +240,7 @@ func (s *snapshot) ModWhy(ctx context.Context, fh source.FileHandle) (map[string
}

// Await result.
v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
v, err := s.awaitPromise(ctx, entry)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/lsp/cache/mod_tidy.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (s *snapshot) ModTidy(ctx context.Context, pm *source.ParsedModule) (*sourc
}

// Await result.
v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
v, err := s.awaitPromise(ctx, entry)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/lsp/cache/mod_vuln.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (s *snapshot) ModVuln(ctx context.Context, modURI span.URI) (*govulncheck.R
}

// Await result.
v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
v, err := s.awaitPromise(ctx, entry)
if err != nil {
return nil, err
}
Expand Down
17 changes: 9 additions & 8 deletions gopls/internal/lsp/cache/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/gocommand"
"golang.org/x/tools/internal/imports"
"golang.org/x/tools/internal/memoize"
"golang.org/x/tools/internal/persistent"
"golang.org/x/tools/internal/xcontext"
)
Expand Down Expand Up @@ -169,18 +170,18 @@ func (s *Session) createView(ctx context.Context, name string, folder span.URI,
backgroundCtx: backgroundCtx,
cancel: cancel,
store: s.cache.store,
packages: persistent.NewMap(packageIDLessInterface),
packages: new(persistent.Map[PackageID, *packageHandle]),
meta: new(metadataGraph),
files: newFilesMap(),
activePackages: persistent.NewMap(packageIDLessInterface),
symbolizeHandles: persistent.NewMap(uriLessInterface),
activePackages: new(persistent.Map[PackageID, *Package]),
symbolizeHandles: new(persistent.Map[span.URI, *memoize.Promise]),
workspacePackages: make(map[PackageID]PackagePath),
unloadableFiles: make(map[span.URI]struct{}),
parseModHandles: persistent.NewMap(uriLessInterface),
parseWorkHandles: persistent.NewMap(uriLessInterface),
modTidyHandles: persistent.NewMap(uriLessInterface),
modVulnHandles: persistent.NewMap(uriLessInterface),
modWhyHandles: persistent.NewMap(uriLessInterface),
parseModHandles: new(persistent.Map[span.URI, *memoize.Promise]),
parseWorkHandles: new(persistent.Map[span.URI, *memoize.Promise]),
modTidyHandles: new(persistent.Map[span.URI, *memoize.Promise]),
modVulnHandles: new(persistent.Map[span.URI, *memoize.Promise]),
modWhyHandles: new(persistent.Map[span.URI, *memoize.Promise]),
knownSubdirs: newKnownDirsSet(),
workspaceModFiles: wsModFiles,
workspaceModFilesErr: wsModFilesErr,
Expand Down
27 changes: 13 additions & 14 deletions gopls/internal/lsp/cache/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ type snapshot struct {

// symbolizeHandles maps each file URI to a handle for the future
// result of computing the symbols declared in that file.
symbolizeHandles *persistent.Map // from span.URI to *memoize.Promise[symbolizeResult]
symbolizeHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[symbolizeResult]

// packages maps a packageKey to a *packageHandle.
// It may be invalidated when a file's content changes.
Expand All @@ -110,13 +110,13 @@ type snapshot struct {
// - packages.Get(id).meta == meta.metadata[id] for all ids
// - if a package is in packages, then all of its dependencies should also
// be in packages, unless there is a missing import
packages *persistent.Map // from packageID to *packageHandle
packages *persistent.Map[PackageID, *packageHandle]

// activePackages maps a package ID to a memoized active package, or nil if
// the package is known not to be open.
//
// IDs not contained in the map are not known to be open or not open.
activePackages *persistent.Map // from packageID to *Package
activePackages *persistent.Map[PackageID, *Package]

// workspacePackages contains the workspace's packages, which are loaded
// when the view is created. It contains no intermediate test variants.
Expand All @@ -137,18 +137,18 @@ type snapshot struct {

// parseModHandles keeps track of any parseModHandles for the snapshot.
// The handles need not refer to only the view's go.mod file.
parseModHandles *persistent.Map // from span.URI to *memoize.Promise[parseModResult]
parseModHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[parseModResult]

// parseWorkHandles keeps track of any parseWorkHandles for the snapshot.
// The handles need not refer to only the view's go.work file.
parseWorkHandles *persistent.Map // from span.URI to *memoize.Promise[parseWorkResult]
parseWorkHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[parseWorkResult]

// Preserve go.mod-related handles to avoid garbage-collecting the results
// of various calls to the go command. The handles need not refer to only
// the view's go.mod file.
modTidyHandles *persistent.Map // from span.URI to *memoize.Promise[modTidyResult]
modWhyHandles *persistent.Map // from span.URI to *memoize.Promise[modWhyResult]
modVulnHandles *persistent.Map // from span.URI to *memoize.Promise[modVulnResult]
modTidyHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[modTidyResult]
modWhyHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[modWhyResult]
modVulnHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[modVulnResult]

// knownSubdirs is the set of subdirectory URIs in the workspace,
// used to create glob patterns for file watching.
Expand Down Expand Up @@ -871,7 +871,7 @@ func (s *snapshot) getActivePackage(id PackageID) *Package {
defer s.mu.Unlock()

if value, ok := s.activePackages.Get(id); ok {
return value.(*Package) // possibly nil, if we have already checked this id.
return value
}
return nil
}
Expand All @@ -895,7 +895,7 @@ func (s *snapshot) setActivePackage(id PackageID, pkg *Package) {

func (s *snapshot) resetActivePackagesLocked() {
s.activePackages.Destroy()
s.activePackages = persistent.NewMap(packageIDLessInterface)
s.activePackages = new(persistent.Map[PackageID, *Package])
}

const fileExtensions = "go,mod,sum,work"
Expand Down Expand Up @@ -2189,7 +2189,7 @@ func (s *snapshot) clone(ctx, bgCtx context.Context, changes map[span.URI]*fileC
result.packages.Delete(id)
} else {
if entry, hit := result.packages.Get(id); hit {
ph := entry.(*packageHandle).clone(false)
ph := entry.clone(false)
result.packages.Set(id, ph, nil)
}
}
Expand Down Expand Up @@ -2291,12 +2291,11 @@ func (s *snapshot) clone(ctx, bgCtx context.Context, changes map[span.URI]*fileC
// changed that happens not to be present in the map, but that's OK: the goal
// of this function is to guarantee that IF the nearest mod file is present in
// the map, it is invalidated.
func deleteMostRelevantModFile(m *persistent.Map, changed span.URI) {
func deleteMostRelevantModFile(m *persistent.Map[span.URI, *memoize.Promise], changed span.URI) {
var mostRelevant span.URI
changedFile := changed.Filename()

m.Range(func(key, value interface{}) {
modURI := key.(span.URI)
m.Range(func(modURI span.URI, _ *memoize.Promise) {
if len(modURI) > len(mostRelevant) {
if source.InDir(filepath.Dir(modURI.Filename()), changedFile) {
mostRelevant = modURI
Expand Down
3 changes: 1 addition & 2 deletions gopls/internal/lsp/cache/symbols.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"golang.org/x/tools/gopls/internal/lsp/protocol"
"golang.org/x/tools/gopls/internal/lsp/source"
"golang.org/x/tools/gopls/internal/span"
"golang.org/x/tools/internal/memoize"
)

// symbolize returns the result of symbolizing the file identified by uri, using a cache.
Expand Down Expand Up @@ -51,7 +50,7 @@ func (s *snapshot) symbolize(ctx context.Context, uri span.URI) ([]source.Symbol
}

// Await result.
v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
v, err := s.awaitPromise(ctx, entry)
if err != nil {
return nil, err
}
Expand Down
52 changes: 52 additions & 0 deletions internal/constraints/constraint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package constraints defines a set of useful constraints to be used
// with type parameters.
package constraints

// Copied from x/exp/constraints.

// Signed is a constraint that permits any signed integer type.
// If future releases of Go add new predeclared signed integer types,
// this constraint will be modified to include them.
type Signed interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}

// Unsigned is a constraint that permits any unsigned integer type.
// If future releases of Go add new predeclared unsigned integer types,
// this constraint will be modified to include them.
type Unsigned interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}

// Integer is a constraint that permits any integer type.
// If future releases of Go add new predeclared integer types,
// this constraint will be modified to include them.
type Integer interface {
Signed | Unsigned
}

// Float is a constraint that permits any floating-point type.
// If future releases of Go add new predeclared floating-point types,
// this constraint will be modified to include them.
type Float interface {
~float32 | ~float64
}

// Complex is a constraint that permits any complex numeric type.
// If future releases of Go add new predeclared complex numeric types,
// this constraint will be modified to include them.
type Complex interface {
~complex64 | ~complex128
}

// Ordered is a constraint that permits any ordered type: any type
// that supports the operators < <= >= >.
// If future releases of Go add new ordered types,
// this constraint will be modified to include them.
type Ordered interface {
Integer | Float | ~string
}
Loading

0 comments on commit 010e045

Please sign in to comment.