cmd/go: add and use cmd/go/internal/slices.Clip

This will be part of the standard library soon and then
cmd/go can use it directly, but I am writing a few more instances
of this pattern today and wanted to clean these up first.

Change-Id: I3a7336039949ffe95a403aed08d79206c91eafb7
Reviewed-on: https://go-review.googlesource.com/c/go/+/464115
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Russ Cox <rsc@golang.org>
diff --git a/src/cmd/go/internal/generate/generate.go b/src/cmd/go/internal/generate/generate.go
index 3eda6c7..160a872 100644
--- a/src/cmd/go/internal/generate/generate.go
+++ b/src/cmd/go/internal/generate/generate.go
@@ -25,6 +25,7 @@
 	"cmd/go/internal/cfg"
 	"cmd/go/internal/load"
 	"cmd/go/internal/modload"
+	"cmd/go/internal/slices"
 	"cmd/go/internal/str"
 	"cmd/go/internal/work"
 )
@@ -461,7 +462,7 @@
 	if g.commands[command] != nil {
 		g.errorf("command %q multiply defined", command)
 	}
-	g.commands[command] = words[2:len(words):len(words)] // force later append to make copy
+	g.commands[command] = slices.Clip(words[2:])
 }
 
 // exec runs the command specified by the argument. The first word is
diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go
index aa59611..fddcdb6 100644
--- a/src/cmd/go/internal/modload/buildlist.go
+++ b/src/cmd/go/internal/modload/buildlist.go
@@ -9,6 +9,7 @@
 	"cmd/go/internal/cfg"
 	"cmd/go/internal/mvs"
 	"cmd/go/internal/par"
+	"cmd/go/internal/slices"
 	"context"
 	"fmt"
 	"os"
@@ -23,11 +24,6 @@
 	"golang.org/x/mod/semver"
 )
 
-// capVersionSlice returns s with its cap reduced to its length.
-func capVersionSlice(s []module.Version) []module.Version {
-	return s[:len(s):len(s)]
-}
-
 // A Requirements represents a logically-immutable set of root module requirements.
 type Requirements struct {
 	// pruning is the pruning at which the requirement graph is computed.
@@ -108,7 +104,7 @@
 	if pruning == workspace {
 		return &Requirements{
 			pruning:        pruning,
-			rootModules:    capVersionSlice(rootModules),
+			rootModules:    slices.Clip(rootModules),
 			maxRootVersion: nil,
 			direct:         direct,
 		}
@@ -135,7 +131,7 @@
 
 	rs := &Requirements{
 		pruning:        pruning,
-		rootModules:    capVersionSlice(rootModules),
+		rootModules:    slices.Clip(rootModules),
 		maxRootVersion: make(map[string]string, len(rootModules)),
 		direct:         direct,
 	}
@@ -470,7 +466,7 @@
 // and may rely on it not to be modified.
 func (mg *ModuleGraph) BuildList() []module.Version {
 	mg.buildListOnce.Do(func() {
-		mg.buildList = capVersionSlice(mg.g.BuildList())
+		mg.buildList = slices.Clip(mg.g.BuildList())
 	})
 	return mg.buildList
 }
diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go
index 34b00d5..b23966d 100644
--- a/src/cmd/go/internal/modload/init.go
+++ b/src/cmd/go/internal/modload/init.go
@@ -26,6 +26,7 @@
 	"cmd/go/internal/modconv"
 	"cmd/go/internal/modfetch"
 	"cmd/go/internal/search"
+	"cmd/go/internal/slices"
 
 	"golang.org/x/mod/modfile"
 	"golang.org/x/mod/module"
@@ -990,7 +991,7 @@
 	}
 	modRootContainingCWD := findModuleRoot(base.Cwd())
 	mainModules := &MainModuleSet{
-		versions:           ms[:len(ms):len(ms)],
+		versions:           slices.Clip(ms),
 		inGorootSrc:        map[module.Version]bool{},
 		pathPrefix:         map[module.Version]string{},
 		modRoot:            map[module.Version]string{},
diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go
index c3764b4..4affdc0 100644
--- a/src/cmd/go/internal/modload/query.go
+++ b/src/cmd/go/internal/modload/query.go
@@ -23,6 +23,7 @@
 	"cmd/go/internal/modfetch/codehost"
 	"cmd/go/internal/modinfo"
 	"cmd/go/internal/search"
+	"cmd/go/internal/slices"
 	"cmd/go/internal/str"
 	"cmd/go/internal/trace"
 	"cmd/internal/pkgpattern"
@@ -768,7 +769,7 @@
 			Query:   query,
 		}
 	}
-	return results[:len(results):len(results)], modOnly, err
+	return slices.Clip(results), modOnly, err
 }
 
 // modulePrefixesExcludingTarget returns all prefixes of path that may plausibly
diff --git a/src/cmd/go/internal/mvs/graph.go b/src/cmd/go/internal/mvs/graph.go
index c5de486..94835bc 100644
--- a/src/cmd/go/internal/mvs/graph.go
+++ b/src/cmd/go/internal/mvs/graph.go
@@ -5,6 +5,7 @@
 package mvs
 
 import (
+	"cmd/go/internal/slices"
 	"fmt"
 
 	"golang.org/x/mod/module"
@@ -30,7 +31,7 @@
 func NewGraph(cmp func(v1, v2 string) int, roots []module.Version) *Graph {
 	g := &Graph{
 		cmp:      cmp,
-		roots:    roots[:len(roots):len(roots)],
+		roots:    slices.Clip(roots),
 		required: make(map[module.Version][]module.Version),
 		isRoot:   make(map[module.Version]bool),
 		selected: make(map[string]string),
@@ -64,7 +65,7 @@
 
 	// Truncate reqs to its capacity to avoid aliasing bugs if it is later
 	// returned from RequiredBy and appended to.
-	reqs = reqs[:len(reqs):len(reqs)]
+	reqs = slices.Clip(reqs)
 
 	if _, dup := g.required[m]; dup {
 		panic(fmt.Sprintf("requirements of %v have already been set", m))
diff --git a/src/cmd/go/internal/slices/slices.go b/src/cmd/go/internal/slices/slices.go
new file mode 100644
index 0000000..a0adcf4
--- /dev/null
+++ b/src/cmd/go/internal/slices/slices.go
@@ -0,0 +1,12 @@
+// Copyright 2023 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.
+
+// TODO: Replace with slices package when it lands in standard library.
+
+package slices
+
+// Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
+func Clip[S ~[]E, E any](s S) S {
+	return s[:len(s):len(s)]
+}
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index be024f4..48760ba 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -28,6 +28,7 @@
 	"cmd/go/internal/lockedfile"
 	"cmd/go/internal/modload"
 	"cmd/go/internal/search"
+	"cmd/go/internal/slices"
 	"cmd/go/internal/str"
 	"cmd/go/internal/trace"
 	"cmd/go/internal/work"
@@ -1284,7 +1285,7 @@
 	cmd := exec.CommandContext(ctx, args[0], args[1:]...)
 	cmd.Dir = a.Package.Dir
 
-	env := cfg.OrigEnv[:len(cfg.OrigEnv):len(cfg.OrigEnv)]
+	env := slices.Clip(cfg.OrigEnv)
 	env = base.AppendPATH(env)
 	env = base.AppendPWD(env, cmd.Dir)
 	cmd.Env = env
diff --git a/src/cmd/go/internal/vcweb/git.go b/src/cmd/go/internal/vcweb/git.go
index 5f9864e..2168d52 100644
--- a/src/cmd/go/internal/vcweb/git.go
+++ b/src/cmd/go/internal/vcweb/git.go
@@ -5,6 +5,7 @@
 package vcweb
 
 import (
+	"cmd/go/internal/slices"
 	"log"
 	"net/http"
 	"net/http/cgi"
@@ -41,7 +42,7 @@
 		Logger: logger,
 		Args:   []string{"http-backend"},
 		Dir:    dir,
-		Env: append(env[:len(env):len(env)],
+		Env: append(slices.Clip(env),
 			"GIT_PROJECT_ROOT="+dir,
 			"GIT_HTTP_EXPORT_ALL=1",
 		),
diff --git a/src/cmd/go/internal/vcweb/hg.go b/src/cmd/go/internal/vcweb/hg.go
index 8687171..3c45aca 100644
--- a/src/cmd/go/internal/vcweb/hg.go
+++ b/src/cmd/go/internal/vcweb/hg.go
@@ -6,6 +6,7 @@
 
 import (
 	"bufio"
+	"cmd/go/internal/slices"
 	"context"
 	"errors"
 	"io"
@@ -54,7 +55,7 @@
 
 		cmd := exec.CommandContext(ctx, h.hgPath, "serve", "--port", "0", "--address", "localhost", "--accesslog", os.DevNull, "--name", "vcweb", "--print-url")
 		cmd.Dir = dir
-		cmd.Env = append(env[:len(env):len(env)], "PWD="+dir)
+		cmd.Env = append(slices.Clip(env), "PWD="+dir)
 
 		cmd.Cancel = func() error {
 			err := cmd.Process.Signal(os.Interrupt)
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 7f2924f..8dde0a9 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -36,6 +36,7 @@
 	"cmd/go/internal/fsys"
 	"cmd/go/internal/load"
 	"cmd/go/internal/modload"
+	"cmd/go/internal/slices"
 	"cmd/go/internal/str"
 	"cmd/go/internal/trace"
 	"cmd/internal/quoted"
@@ -2490,7 +2491,7 @@
 			} else {
 				to = filepath.Join("/_", toPath)
 			}
-			flags = append(flags[:len(flags):len(flags)], "-fdebug-prefix-map="+from+"="+to)
+			flags = append(slices.Clip(flags), "-fdebug-prefix-map="+from+"="+to)
 		}
 	}