diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5416122c..2d30a1b8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,8 +12,8 @@ jobs: fail-fast: false matrix: go-version: - - '1.22.x' - '1.23.x' + - '1.24.x' os: - ubuntu-latest - macos-latest @@ -33,7 +33,7 @@ jobs: go test -race ./... - name: Tidy - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.23.x' # no need to do this everywhere + if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.24.x' # no need to do this everywhere run: | go mod tidy diff --git a/cache/cache.go b/cache/cache.go index 93c90535..cf8a5bac 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -55,7 +55,7 @@ func Open(dir string) (*Cache, error) { if !info.IsDir() { return nil, &fs.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")} } - for i := 0; i < 256; i++ { + for i := range 256 { name := filepath.Join(dir, fmt.Sprintf("%02x", i)) if err := os.MkdirAll(name, 0777); err != nil { return nil, err @@ -332,7 +332,7 @@ func (c *Cache) Trim() error { // We subtract an additional mtimeInterval // to account for the imprecision of our "last used" mtimes. cutoff := now.Add(-trimLimit - mtimeInterval) - for i := 0; i < 256; i++ { + for i := range 256 { subdir := filepath.Join(c.dir, fmt.Sprintf("%02x", i)) c.trimSubdir(subdir, cutoff) } diff --git a/cache/cache_test.go b/cache/cache_test.go index 5ff84c2b..9a1a732c 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -80,7 +80,7 @@ func TestGrowth(t *testing.T) { n = 10 } - for i := 0; i < n; i++ { + for i := range n { if err := c.putIndexEntry(dummyID(i), dummyID(i*99), int64(i)*101, true); err != nil { t.Fatalf("addIndexEntry: %v", err) } @@ -93,7 +93,7 @@ func TestGrowth(t *testing.T) { t.Errorf("Get(%x) = %x, %d, want %x, %d", id, entry.OutputID, entry.Size, dummyID(i*99), int64(i)*101) } } - for i := 0; i < n; i++ { + for i := range n { id := ActionID(dummyID(i)) entry, err := c.Get(id) if err != nil { diff --git a/cmd/testscript/main.go b/cmd/testscript/main.go index 4e6832f2..fbf66867 100644 --- a/cmd/testscript/main.go +++ b/cmd/testscript/main.go @@ -184,11 +184,11 @@ type runT struct { failed atomic.Bool } -func (r *runT) Skip(is ...interface{}) { +func (r *runT) Skip(is ...any) { panic(skipRun) } -func (r *runT) Fatal(is ...interface{}) { +func (r *runT) Fatal(is ...any) { r.Log(is...) r.FailNow() } @@ -197,7 +197,7 @@ func (r *runT) Parallel() { // TODO run tests in parallel. } -func (r *runT) Log(is ...interface{}) { +func (r *runT) Log(is ...any) { msg := fmt.Sprint(is...) if r.stdinTempFile != "" { msg = strings.ReplaceAll(msg, r.stdinTempFile, "") diff --git a/cmd/txtar-addmod/addmod.go b/cmd/txtar-addmod/addmod.go index 70714e73..9e61cedb 100644 --- a/cmd/txtar-addmod/addmod.go +++ b/cmd/txtar-addmod/addmod.go @@ -55,7 +55,7 @@ It is acceptable to edit the archive afterward to remove or shorten files. var tmpdir string -func fatalf(format string, args ...interface{}) { +func fatalf(format string, args ...any) { os.RemoveAll(tmpdir) log.Fatalf(format, args...) } @@ -150,7 +150,7 @@ func main() { filePrefix = ".gomodproxy/" + modDir + "/" } else { // No comment if we're writing to stdout. - a.Comment = []byte(fmt.Sprintf("module %s\n\n", title)) + a.Comment = fmt.Appendf(nil, "module %s\n\n", title) } a.Files = []txtar.File{ {Name: filePrefix + ".mod", Data: mod}, diff --git a/diff/diff.go b/diff/diff.go index 0aeeb75e..9bd8bd78 100644 --- a/diff/diff.go +++ b/diff/diff.go @@ -116,10 +116,7 @@ func Diff(oldName string, old []byte, newName string, new []byte) []byte { // End chunk with common lines for context. if len(ctext) > 0 { - n := end.x - start.x - if n > C { - n = C - } + n := min(end.x-start.x, C) for _, s := range x[start.x : start.x+n] { ctext = append(ctext, " "+s) count.x++ @@ -234,7 +231,7 @@ func tgs(x, y []string) []pair { for i := range T { T[i] = n + 1 } - for i := 0; i < n; i++ { + for i := range n { k := sort.Search(n, func(k int) bool { return T[k] >= J[i] }) diff --git a/fmtsort/sort.go b/fmtsort/sort.go index 7f518541..6af8c7f7 100644 --- a/fmtsort/sort.go +++ b/fmtsort/sort.go @@ -143,14 +143,14 @@ func compare(aVal, bVal reflect.Value) int { return 0 } case reflect.Struct: - for i := 0; i < aVal.NumField(); i++ { + for i := range aVal.NumField() { if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 { return c } } return 0 case reflect.Array: - for i := 0; i < aVal.Len(); i++ { + for i := range aVal.Len() { if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 { return c } diff --git a/fmtsort/sort_test.go b/fmtsort/sort_test.go index 88e5bb88..dfe72620 100644 --- a/fmtsort/sort_test.go +++ b/fmtsort/sort_test.go @@ -36,12 +36,12 @@ var compareTests = [][]reflect.Value{ ct(reflect.TypeOf(chans[0]), chans[0], chans[1], chans[2]), ct(reflect.TypeOf(toy{}), toy{0, 1}, toy{0, 2}, toy{1, -1}, toy{1, 1}), ct(reflect.TypeOf([2]int{}), [2]int{1, 1}, [2]int{1, 2}, [2]int{2, 0}), - ct(reflect.TypeOf(interface{}(interface{}(0))), iFace, 1, 2, 3), + ct(reflect.TypeOf(any(any(0))), iFace, 1, 2, 3), } -var iFace interface{} +var iFace any -func ct(typ reflect.Type, args ...interface{}) []reflect.Value { +func ct(typ reflect.Type, args ...any) []reflect.Value { value := make([]reflect.Value, len(args)) for i, v := range args { x := reflect.ValueOf(v) @@ -82,9 +82,9 @@ func TestCompare(t *testing.T) { } type sortTest struct { - data interface{} // Always a map. - print string // Printed result using our custom printer. - printBrokenNaNs string // Printed result when NaN support is broken (pre Go1.12). + data any // Always a map. + print string // Printed result using our custom printer. + printBrokenNaNs string // Printed result when NaN support is broken (pre Go1.12). } var sortTests = []sortTest{ @@ -132,7 +132,7 @@ var sortTests = []sortTest{ }, } -func sprint(data interface{}) string { +func sprint(data any) string { om := fmtsort.Sort(reflect.ValueOf(data)) if om == nil { return "nil" @@ -219,7 +219,7 @@ func TestInterface(t *testing.T) { // A map containing multiple concrete types should be sorted by type, // then value. However, the relative ordering of types is unspecified, // so test this by checking the presence of sorted subgroups. - m := map[interface{}]string{ + m := map[any]string{ [2]int{1, 0}: "", [2]int{0, 1}: "", true: "", diff --git a/go.mod b/go.mod index 8a504e7b..01ce72eb 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/rogpeppe/go-internal -go 1.22.0 +go 1.23 require ( golang.org/x/mod v0.21.0 diff --git a/goproxytest/allhex.go b/goproxytest/allhex.go index c77e52e4..6a4cc7f6 100644 --- a/goproxytest/allhex.go +++ b/goproxytest/allhex.go @@ -8,7 +8,7 @@ package goproxytest // allHex reports whether the revision rev is entirely lower-case hexadecimal digits. func allHex(rev string) bool { - for i := 0; i < len(rev); i++ { + for i := range len(rev) { c := rev[i] if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' { continue diff --git a/goproxytest/proxy.go b/goproxytest/proxy.go index e8fe8a7c..eb6ba0b4 100644 --- a/goproxytest/proxy.go +++ b/goproxytest/proxy.go @@ -239,7 +239,7 @@ func (srv *Server) handler(w http.ResponseWriter, r *http.Request) { zip []byte err error } - c := srv.zipCache.Do(a, func() interface{} { + c := srv.zipCache.Do(a, func() any { var buf bytes.Buffer z := zip.NewWriter(&buf) for _, f := range a.Files { @@ -305,7 +305,7 @@ func (srv *Server) readArchive(path, vers string) *txtar.Archive { name := filepath.Join(srv.dir, prefix+"_"+encVers) txtName := name + ".txt" txtarName := name + ".txtar" - a := srv.archiveCache.Do(name, func() interface{} { + a := srv.archiveCache.Do(name, func() any { a, err := txtar.ParseFile(txtarName) if os.IsNotExist(err) { // fall back to trying with the .txt extension diff --git a/imports/read.go b/imports/read.go index 58c2abdc..010959f9 100644 --- a/imports/read.go +++ b/imports/read.go @@ -123,7 +123,7 @@ func (r *importReader) nextByte(skipSpace bool) byte { // If the keyword is not present, readKeyword records a syntax error. func (r *importReader) readKeyword(kw string) { r.peekByte(true) - for i := 0; i < len(kw); i++ { + for i := range len(kw) { if r.nextByte(false) != kw[i] { r.syntaxError() return diff --git a/par/work.go b/par/work.go index a568c86f..73efff86 100644 --- a/par/work.go +++ b/par/work.go @@ -14,24 +14,24 @@ import ( // Work manages a set of work items to be executed in parallel, at most once each. // The items in the set must all be valid map keys. type Work struct { - f func(interface{}) // function to run for each item - running int // total number of runners + f func(any) // function to run for each item + running int // total number of runners mu sync.Mutex - added map[interface{}]bool // items added to set - todo []interface{} // items yet to be run - wait sync.Cond // wait when todo is empty - waiting int // number of runners waiting for todo + added map[any]bool // items added to set + todo []any // items yet to be run + wait sync.Cond // wait when todo is empty + waiting int // number of runners waiting for todo } func (w *Work) init() { if w.added == nil { - w.added = make(map[interface{}]bool) + w.added = make(map[any]bool) } } // Add adds item to the work set, if it hasn't already been added. -func (w *Work) Add(item interface{}) { +func (w *Work) Add(item any) { w.mu.Lock() w.init() if !w.added[item] { @@ -51,7 +51,7 @@ func (w *Work) Add(item interface{}) { // before calling Do (or else Do returns immediately), // but it is allowed for f(item) to add new items to the set. // Do should only be used once on a given Work. -func (w *Work) Do(n int, f func(item interface{})) { +func (w *Work) Do(n int, f func(item any)) { if n < 1 { panic("par.Work.Do: n < 1") } @@ -63,7 +63,7 @@ func (w *Work) Do(n int, f func(item interface{})) { w.f = f w.wait.L = &w.mu - for i := 0; i < n-1; i++ { + for range n - 1 { go w.runner() } w.runner() @@ -110,13 +110,13 @@ type Cache struct { type cacheEntry struct { done uint32 mu sync.Mutex - result interface{} + result any } // Do calls the function f if and only if Do is being called for the first time with this key. // No call to Do with a given key returns until the one call to f returns. // Do returns the value returned by the one call to f. -func (c *Cache) Do(key interface{}, f func() interface{}) interface{} { +func (c *Cache) Do(key any, f func() any) any { entryIface, ok := c.m.Load(key) if !ok { entryIface, _ = c.m.LoadOrStore(key, new(cacheEntry)) @@ -136,7 +136,7 @@ func (c *Cache) Do(key interface{}, f func() interface{}) interface{} { // Get returns the cached result associated with key. // It returns nil if there is no such result. // If the result for key is being computed, Get does not wait for the computation to finish. -func (c *Cache) Get(key interface{}) interface{} { +func (c *Cache) Get(key any) any { entryIface, ok := c.m.Load(key) if !ok { return nil diff --git a/par/work_test.go b/par/work_test.go index f104bc41..61e63d22 100644 --- a/par/work_test.go +++ b/par/work_test.go @@ -16,7 +16,7 @@ func TestWork(t *testing.T) { const N = 10000 n := int32(0) w.Add(N) - w.Do(100, func(x interface{}) { + w.Do(100, func(x any) { atomic.AddInt32(&n, 1) i := x.(int) if i >= 2 { @@ -32,15 +32,15 @@ func TestWork(t *testing.T) { } func TestWorkParallel(t *testing.T) { - for tries := 0; tries < 10; tries++ { + for range 10 { var w Work const N = 100 - for i := 0; i < N; i++ { + for i := range N { w.Add(i) } start := time.Now() var n int32 - w.Do(N, func(x interface{}) { + w.Do(N, func(x any) { time.Sleep(1 * time.Millisecond) atomic.AddInt32(&n, +1) }) @@ -58,19 +58,19 @@ func TestCache(t *testing.T) { var cache Cache n := 1 - v := cache.Do(1, func() interface{} { n++; return n }) + v := cache.Do(1, func() any { n++; return n }) if v != 2 { t.Fatalf("cache.Do(1) did not run f") } - v = cache.Do(1, func() interface{} { n++; return n }) + v = cache.Do(1, func() any { n++; return n }) if v != 2 { t.Fatalf("cache.Do(1) ran f again!") } - v = cache.Do(2, func() interface{} { n++; return n }) + v = cache.Do(2, func() any { n++; return n }) if v != 3 { t.Fatalf("cache.Do(2) did not run f") } - v = cache.Do(1, func() interface{} { n++; return n }) + v = cache.Do(1, func() any { n++; return n }) if v != 2 { t.Fatalf("cache.Do(1) did not returned saved value from original cache.Do(1)") } diff --git a/testscript/cmd.go b/testscript/cmd.go index e04d26e4..55abd31d 100644 --- a/testscript/cmd.go +++ b/testscript/cmd.go @@ -13,6 +13,7 @@ import ( "path/filepath" "regexp" "runtime" + "slices" "strconv" "strings" @@ -592,7 +593,7 @@ func (ts *TestScript) waitBackgroundOne(bgName string) { // Remove this process from the list of running background processes. for i := range ts.background { if bg == &ts.background[i] { - ts.background = append(ts.background[:i], ts.background[i+1:]...) + ts.background = slices.Delete(ts.background, i, i+1) break } } diff --git a/testscript/testscript.go b/testscript/testscript.go index cc72cc9a..ec0c8e12 100644 --- a/testscript/testscript.go +++ b/testscript/testscript.go @@ -70,14 +70,14 @@ type Env struct { // Values holds a map of arbitrary values for use by custom // testscript commands. This enables Setup to pass arbitrary // values (not just strings) through to custom commands. - Values map[interface{}]interface{} + Values map[any]any ts *TestScript } // Value returns a value from Env.Values, or nil if no // value was set by Setup. -func (ts *TestScript) Value(key interface{}) interface{} { +func (ts *TestScript) Value(key any) any { return ts.values[key] } @@ -214,10 +214,10 @@ func Run(t *testing.T, p Params) { // T holds all the methods of the *testing.T type that // are used by testscript. type T interface { - Skip(...interface{}) - Fatal(...interface{}) + Skip(...any) + Fatal(...any) Parallel() - Log(...interface{}) + Log(...any) FailNow() Run(string, func(T)) // Verbose is usually implemented by the testing package @@ -376,30 +376,30 @@ type TestScript struct { params Params t T testTempDir string - workdir string // temporary work dir ($WORK) - log bytes.Buffer // test execution log (printed at end of test) - mark int // offset of next log truncation - cd string // current directory during test execution; initially $WORK/gopath/src - name string // short name of test ("foo") - file string // full file name ("testdata/script/foo.txt") - lineno int // line number currently executing - line string // line currently executing - env []string // environment list (for os/exec) - envMap map[string]string // environment mapping (matches env; on Windows keys are lowercase) - values map[interface{}]interface{} // values for custom commands - stdin string // standard input to next 'go' command; set by 'stdin' command. - stdout string // standard output from last 'go' command; for 'stdout' command - stderr string // standard error from last 'go' command; for 'stderr' command - ttyin string // terminal input; set by 'ttyin' command - stdinPty bool // connect pty to standard input; set by 'ttyin -stdin' command - ttyout string // terminal output; for 'ttyout' command - stopped bool // test wants to stop early - start time.Time // time phase started - background []backgroundCmd // backgrounded 'exec' and 'go' commands - deferred func() // deferred cleanup actions. - archive *txtar.Archive // the testscript being run. - scriptFiles map[string]string // files stored in the txtar archive (absolute paths -> path in script) - scriptUpdates map[string]string // updates to testscript files via UpdateScripts. + workdir string // temporary work dir ($WORK) + log bytes.Buffer // test execution log (printed at end of test) + mark int // offset of next log truncation + cd string // current directory during test execution; initially $WORK/gopath/src + name string // short name of test ("foo") + file string // full file name ("testdata/script/foo.txt") + lineno int // line number currently executing + line string // line currently executing + env []string // environment list (for os/exec) + envMap map[string]string // environment mapping (matches env; on Windows keys are lowercase) + values map[any]any // values for custom commands + stdin string // standard input to next 'go' command; set by 'stdin' command. + stdout string // standard output from last 'go' command; for 'stdout' command + stderr string // standard error from last 'go' command; for 'stderr' command + ttyin string // terminal input; set by 'ttyin' command + stdinPty bool // connect pty to standard input; set by 'ttyin -stdin' command + ttyout string // terminal output; for 'ttyout' command + stopped bool // test wants to stop early + start time.Time // time phase started + background []backgroundCmd // backgrounded 'exec' and 'go' commands + deferred func() // deferred cleanup actions. + archive *txtar.Archive // the testscript being run. + scriptFiles map[string]string // files stored in the txtar archive (absolute paths -> path in script) + scriptUpdates map[string]string // updates to testscript files via UpdateScripts. // runningBuiltin indicates if we are running a user-supplied builtin // command. These commands are specified via Params.Cmds. @@ -475,7 +475,7 @@ func (ts *TestScript) setup() string { "$=$", }, WorkDir: ts.workdir, - Values: make(map[interface{}]interface{}), + Values: make(map[any]any), Cd: ts.workdir, ts: ts, } @@ -552,7 +552,7 @@ func (ts *TestScript) run() { // Insert elapsed time for phase at end of phase marker markTime := func() { if ts.mark > 0 && !ts.start.IsZero() { - afterMark := append([]byte{}, ts.log.Bytes()[ts.mark:]...) + afterMark := slices.Clone(ts.log.Bytes()[ts.mark:]) ts.log.Truncate(ts.mark - 1) // cut \n and afterMark fmt.Fprintf(&ts.log, " (%.3fs)\n", timeSince(ts.start).Seconds()) ts.log.Write(afterMark) @@ -856,7 +856,7 @@ func (ts *TestScript) condition(cond string) (bool, error) { return cond == runtime.GOARCH, nil case strings.HasPrefix(cond, "exec:"): prog := cond[len("exec:"):] - ok := execCache.Do(prog, func() interface{} { + ok := execCache.Do(prog, func() any { _, err := execpath.Look(prog, ts.Getenv) return err == nil }).(bool) @@ -867,10 +867,8 @@ func (ts *TestScript) condition(cond string) (bool, error) { // that will be used. return cond == runtime.Compiler, nil case goVersionRegex.MatchString(cond): - for _, v := range build.Default.ReleaseTags { - if cond == v { - return true, nil - } + if slices.Contains(build.Default.ReleaseTags, cond) { + return true, nil } return false, nil case ts.params.Condition != nil: @@ -968,7 +966,7 @@ func (ts *TestScript) clearBuiltinStd() { } // Logf appends the given formatted message to the test log transcript. -func (ts *TestScript) Logf(format string, args ...interface{}) { +func (ts *TestScript) Logf(format string, args ...any) { format = strings.TrimSuffix(format, "\n") fmt.Fprintf(&ts.log, format, args...) ts.log.WriteByte('\n') @@ -1188,7 +1186,7 @@ func (ts *TestScript) expand(s string) string { } // fatalf aborts the test with the given failure message. -func (ts *TestScript) Fatalf(format string, args ...interface{}) { +func (ts *TestScript) Fatalf(format string, args ...any) { // In user-supplied builtins, the only way we have of aborting // is via Fatalf. Hence if we are aborting from a user-supplied // builtin, it's important we first log stdout and stderr. If diff --git a/testscript/testscript_test.go b/testscript/testscript_test.go index f5190857..b2fea5d6 100644 --- a/testscript/testscript_test.go +++ b/testscript/testscript_test.go @@ -128,7 +128,7 @@ func TestEnv(t *testing.T) { "=", "key=invalid", } { - var panicValue interface{} + var panicValue any func() { defer func() { panicValue = recover() @@ -466,7 +466,7 @@ func waitFile(ts *TestScript, neg bool, args []string) { ts.Fatalf("usage: waitfile file") } path := ts.MkAbs(args[0]) - for i := 0; i < 100; i++ { + for range 100 { _, err := os.Stat(path) if err == nil { return @@ -487,18 +487,18 @@ type fakeT struct { var errAbort = errors.New("abort test") -func (t *fakeT) Skip(args ...interface{}) { +func (t *fakeT) Skip(args ...any) { panic(errAbort) } -func (t *fakeT) Fatal(args ...interface{}) { +func (t *fakeT) Fatal(args ...any) { t.Log(args...) t.FailNow() } func (t *fakeT) Parallel() {} -func (t *fakeT) Log(args ...interface{}) { +func (t *fakeT) Log(args ...any) { fmt.Fprint(&t.log, args...) }