diff --git a/builder/build.go b/builder/build.go index dabbe7544e..10bda8d45b 100644 --- a/builder/build.go +++ b/builder/build.go @@ -14,6 +14,7 @@ import ( "fmt" "go/types" "hash/crc32" + "maps" "math/bits" "os" "os/exec" @@ -137,9 +138,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe if _, ok := globalValues[pkgPath]; !ok { globalValues[pkgPath] = map[string]string{} } - for k, v := range vals { - globalValues[pkgPath][k] = v - } + maps.Copy(globalValues[pkgPath], vals) } // Check for a libc dependency. @@ -278,7 +277,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe var embedFileObjects []*compileJob for _, pkg := range lprogram.Sorted() { - pkg := pkg // necessary to avoid a race condition var undefinedGlobals []string for name := range globalValues[pkg.Pkg.Path()] { @@ -775,7 +773,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe // TODO: do this as part of building the package to be able to link the // bitcode files together. for _, pkg := range lprogram.Sorted() { - pkg := pkg for _, filename := range pkg.CFiles { abspath := filepath.Join(pkg.OriginalDir(), filename) job := &compileJob{ @@ -914,7 +911,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe } // Run wasm-opt for wasm binaries - if arch := strings.Split(config.Triple(), "-")[0]; arch == "wasm32" { + if arch, _, _ := strings.Cut(config.Triple(), "-"); arch == "wasm32" { optLevel, _, _ := config.OptLevel() opt := "-" + optLevel diff --git a/builder/builder_test.go b/builder/builder_test.go index 0e0a156d4a..fe4d395792 100644 --- a/builder/builder_test.go +++ b/builder/builder_test.go @@ -47,7 +47,6 @@ func TestClangAttributes(t *testing.T) { targetNames = append(targetNames, "esp32", "esp8266") } for _, targetName := range targetNames { - targetName := targetName t.Run(targetName, func(t *testing.T) { testClangAttributes(t, &compileopts.Options{Target: targetName}) }) diff --git a/builder/cc.go b/builder/cc.go index b2cc739e3b..9cc03790b6 100644 --- a/builder/cc.go +++ b/builder/cc.go @@ -281,7 +281,7 @@ func parseDepFile(s string) ([]string, error) { s = strings.ReplaceAll(s, "\\\n", " ") // Only use the first line, which is expected to begin with "deps:". - line := strings.SplitN(s, "\n", 2)[0] + line, _, _ := strings.Cut(s, "\n") if !strings.HasPrefix(line, "deps:") { return nil, errors.New("readDepFile: expected 'deps:' prefix") } diff --git a/builder/commands.go b/builder/commands.go index d804ee1476..29b33b915a 100644 --- a/builder/commands.go +++ b/builder/commands.go @@ -17,7 +17,7 @@ import ( var commands = map[string][]string{} func init() { - llvmMajor := strings.Split(llvm.Version, ".")[0] + llvmMajor, _, _ := strings.Cut(llvm.Version, ".") commands["clang"] = []string{"clang-" + llvmMajor} commands["ld.lld"] = []string{"ld.lld-" + llvmMajor, "ld.lld"} commands["wasm-ld"] = []string{"wasm-ld-" + llvmMajor, "wasm-ld"} diff --git a/builder/darwin-libsystem.go b/builder/darwin-libsystem.go index d2846f275b..e47b54230e 100644 --- a/builder/darwin-libsystem.go +++ b/builder/darwin-libsystem.go @@ -15,7 +15,7 @@ func makeDarwinLibSystemJob(config *compileopts.Config, tmpdir string) *compileJ return &compileJob{ description: "compile Darwin libSystem.dylib", run: func(job *compileJob) (err error) { - arch := strings.Split(config.Triple(), "-")[0] + arch, _, _ := strings.Cut(config.Triple(), "-") job.result = filepath.Join(tmpdir, "libSystem.dylib") objpath := filepath.Join(tmpdir, "libSystem.o") inpath := filepath.Join(goenv.Get("TINYGOROOT"), "lib/macos-minimal-sdk/src", arch, "libSystem.s") diff --git a/builder/jobs.go b/builder/jobs.go index 116887461e..b4959fe6cf 100644 --- a/builder/jobs.go +++ b/builder/jobs.go @@ -195,11 +195,11 @@ type intHeap struct { sort.IntSlice } -func (h *intHeap) Push(x interface{}) { +func (h *intHeap) Push(x any) { h.IntSlice = append(h.IntSlice, x.(int)) } -func (h *intHeap) Pop() interface{} { +func (h *intHeap) Pop() any { x := h.IntSlice[len(h.IntSlice)-1] h.IntSlice = h.IntSlice[:len(h.IntSlice)-1] return x diff --git a/builder/library.go b/builder/library.go index 1f8abce964..d30a285227 100644 --- a/builder/library.go +++ b/builder/library.go @@ -232,7 +232,6 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ } for _, path := range paths { // Strip leading "../" parts off the path. - path := path cleanpath := path for strings.HasPrefix(cleanpath, "../") { cleanpath = cleanpath[3:] diff --git a/builder/musl.go b/builder/musl.go index 2ce1b19e3a..c3f4fe99cb 100644 --- a/builder/musl.go +++ b/builder/musl.go @@ -28,8 +28,8 @@ func buildMuslAllTypes(arch, muslDir, outputBitsDir string) error { if err != nil { return err } - lines := strings.Split(string(data), "\n") - for _, line := range lines { + lines := strings.SplitSeq(string(data), "\n") + for line := range lines { if strings.HasPrefix(line, "TYPEDEF ") { matches := regexp.MustCompile(`TYPEDEF (.*) ([^ ]*);`).FindStringSubmatch(line) value := matches[1] diff --git a/builder/sizes_test.go b/builder/sizes_test.go index e7c2b763ba..5e809760f7 100644 --- a/builder/sizes_test.go +++ b/builder/sizes_test.go @@ -51,7 +51,6 @@ func TestBinarySize(t *testing.T) { // output varies by binaryen version. } for _, tc := range tests { - tc := tc t.Run(tc.target+"/"+tc.path, func(t *testing.T) { t.Parallel() @@ -85,7 +84,6 @@ func TestSizeFull(t *testing.T) { pkgMatch := regexp.MustCompile(`^[a-z/]+$`) // example: "internal/task" for _, target := range tests { - target := target t.Run(target, func(t *testing.T) { t.Parallel() diff --git a/builder/tools.go b/builder/tools.go index 56d5a58474..33a26ec37e 100644 --- a/builder/tools.go +++ b/builder/tools.go @@ -116,7 +116,7 @@ func parseLLDErrors(text string) error { // This can happen in some cases like with CGo and //go:linkname tricker. if matches := regexp.MustCompile(`^ld.lld(-[0-9]+)?: error: undefined symbol: (.*)\n`).FindStringSubmatch(message); matches != nil { symbolName := matches[2] - for _, line := range strings.Split(message, "\n") { + for line := range strings.SplitSeq(message, "\n") { matches := regexp.MustCompile(`referenced by .* \(((.*):([0-9]+))\)`).FindStringSubmatch(line) if matches != nil { parsedError = true diff --git a/builder/uf2.go b/builder/uf2.go index 62bae5c66a..6a105065ae 100644 --- a/builder/uf2.go +++ b/builder/uf2.go @@ -40,7 +40,7 @@ func convertBinToUF2(input []byte, targetAddr uint32, uf2FamilyID string) ([]byt } bl.SetNumBlocks(len(blocks)) - for i := 0; i < len(blocks); i++ { + for i := range blocks { bl.SetBlockNo(i) bl.SetData(blocks[i]) diff --git a/cgo/cgo.go b/cgo/cgo.go index 16ae5c850e..743bfc9b65 100644 --- a/cgo/cgo.go +++ b/cgo/cgo.go @@ -44,7 +44,7 @@ type cgoPackage struct { tokenFiles map[string]*token.File definedGlobally map[string]ast.Node noescapingFuncs map[string]*noescapingFunc // #cgo noescape lines - anonDecls map[interface{}]string + anonDecls map[any]string cflags []string // CFlags from #cgo lines ldflags []string // LDFlags from #cgo lines visitedFiles map[string][]byte @@ -263,7 +263,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl tokenFiles: map[string]*token.File{}, definedGlobally: map[string]ast.Node{}, noescapingFuncs: map[string]*noescapingFunc{}, - anonDecls: map[interface{}]string{}, + anonDecls: map[any]string{}, visitedFiles: map[string][]byte{}, } @@ -306,7 +306,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl // Find `import "C"` C fragments in the file. p.cgoHeaders = make([]string, len(files)) // combined CGo header fragment for each file for i, f := range files { - var cgoHeader string + var cgoHeader strings.Builder for i := 0; i < len(f.Decls); i++ { decl := f.Decls[i] genDecl, ok := decl.(*ast.GenDecl) @@ -341,7 +341,8 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl // Iterate through all parts of the CGo header. Note that every // // line is a new comment. position := fset.Position(genDecl.Doc.Pos()) - fragment := fmt.Sprintf("# %d %#v\n", position.Line, position.Filename) + var fragment strings.Builder + fragment.WriteString(fmt.Sprintf("# %d %#v\n", position.Line, position.Filename)) for _, comment := range genDecl.Doc.List { // Find all #cgo lines, extract and use their contents, and // replace the lines with spaces (to preserve locations). @@ -358,12 +359,13 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl } else { // comment c = " " + c[2:len(c)-2] } - fragment += c + "\n" + fragment.WriteString(c) + fragment.WriteByte('\n') } - cgoHeader += fragment + cgoHeader.WriteString(fragment.String()) } - p.cgoHeaders[i] = cgoHeader + p.cgoHeaders[i] = cgoHeader.String() } // Define CFlags that will be used while parsing the package. @@ -1221,7 +1223,7 @@ func getPos(node ast.Node) token.Pos { // getUnnamedDeclName creates a name (with the given prefix) for the given C // declaration. This is used for structs, unions, and enums that are often // defined without a name and used in a typedef. -func (p *cgoPackage) getUnnamedDeclName(prefix string, itf interface{}) string { +func (p *cgoPackage) getUnnamedDeclName(prefix string, itf any) string { if name, ok := p.anonDecls[itf]; ok { return name } diff --git a/cgo/cgo_test.go b/cgo/cgo_test.go index f852c7f5f9..bc83eb15b7 100644 --- a/cgo/cgo_test.go +++ b/cgo/cgo_test.go @@ -45,7 +45,6 @@ func TestCGo(t *testing.T) { "flags", "const", } { - name := name // avoid a race condition t.Run(name, func(t *testing.T) { // Read the AST in memory. path := filepath.Join("testdata", name+".go") diff --git a/cgo/libclang.go b/cgo/libclang.go index 1f8e86ba53..fdf519a0d9 100644 --- a/cgo/libclang.go +++ b/cgo/libclang.go @@ -160,7 +160,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c pos := f.getClangLocationPosition(location, unit) f.addError(pos, severity+": "+spelling) } - for i := 0; i < numDiagnostics; i++ { + for i := range numDiagnostics { diagnostic := C.clang_getDiagnostic(unit, C.uint(i)) addDiagnostic(diagnostic) @@ -278,7 +278,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) { Text: strings.Join(doc, "\n"), }) } - for i := 0; i < numArgs; i++ { + for i := range numArgs { arg := C.tinygo_clang_Cursor_getArgument(c, C.uint(i)) argName := getString(C.tinygo_clang_getCursorSpelling(arg)) argType := C.clang_getArgType(cursorType, C.uint(i)) @@ -534,7 +534,7 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient // Get the precise location in the source code. Used for uniquely identifying // source locations. -func (f *cgoFile) getUniqueLocationID(pos token.Pos, cursor C.GoCXCursor) interface{} { +func (f *cgoFile) getUniqueLocationID(pos token.Pos, cursor C.GoCXCursor) any { clangLocation := C.tinygo_clang_getCursorLocation(cursor) var file C.CXFile var line C.unsigned diff --git a/cgo/sync.go b/cgo/sync.go index 64eab30bee..9d3398be66 100644 --- a/cgo/sync.go +++ b/cgo/sync.go @@ -12,17 +12,17 @@ import "C" // C. It is useful if an API uses function pointers and you cannot pass a Go // pointer but only a C pointer. type refMap struct { - refs map[unsafe.Pointer]interface{} + refs map[unsafe.Pointer]any lock sync.Mutex } // Put stores a value in the map. It can later be retrieved using Get. It must // be removed using Remove to avoid memory leaks. -func (m *refMap) Put(v interface{}) unsafe.Pointer { +func (m *refMap) Put(v any) unsafe.Pointer { m.lock.Lock() defer m.lock.Unlock() if m.refs == nil { - m.refs = make(map[unsafe.Pointer]interface{}, 1) + m.refs = make(map[unsafe.Pointer]any, 1) } ref := C.malloc(1) m.refs[ref] = v @@ -31,7 +31,7 @@ func (m *refMap) Put(v interface{}) unsafe.Pointer { // Get returns a stored value previously inserted with Put. Use the same // reference as you got from Put. -func (m *refMap) Get(ref unsafe.Pointer) interface{} { +func (m *refMap) Get(ref unsafe.Pointer) any { m.lock.Lock() defer m.lock.Unlock() return m.refs[ref] diff --git a/compileopts/config.go b/compileopts/config.go index 673de40f95..a5edfd395a 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "regexp" + "slices" "strconv" "strings" @@ -140,13 +141,7 @@ func (c *Config) GC() string { func (c *Config) NeedsStackObjects() bool { switch c.GC() { case "conservative", "custom", "precise", "boehm": - for _, tag := range c.BuildTags() { - if tag == "tinygo.wasm" { - return true - } - } - - return false + return slices.Contains(c.BuildTags(), "tinygo.wasm") default: return false } @@ -245,7 +240,7 @@ func (c *Config) RP2040BootPatch() bool { // Return a canonicalized architecture name, so we don't have to deal with arm* // vs thumb* vs arm64. func CanonicalArchName(triple string) string { - arch := strings.Split(triple, "-")[0] + arch, _, _ := strings.Cut(triple, "-") if arch == "arm64" { return "aarch64" } diff --git a/compileopts/options.go b/compileopts/options.go index d05cfb419f..cb5f24d5c0 100644 --- a/compileopts/options.go +++ b/compileopts/options.go @@ -3,6 +3,7 @@ package compileopts import ( "fmt" "regexp" + "slices" "strings" "time" ) @@ -67,7 +68,7 @@ type Options struct { // Verify performs a validation on the given options, raising an error if options are not valid. func (o *Options) Verify() error { if o.BuildMode != "" { - valid := isInArray(validBuildModeOptions, o.BuildMode) + valid := slices.Contains(validBuildModeOptions, o.BuildMode) if !valid { return fmt.Errorf(`invalid buildmode option '%s': valid values are %s`, o.BuildMode, @@ -75,7 +76,7 @@ func (o *Options) Verify() error { } } if o.GC != "" { - valid := isInArray(validGCOptions, o.GC) + valid := slices.Contains(validGCOptions, o.GC) if !valid { return fmt.Errorf(`invalid gc option '%s': valid values are %s`, o.GC, @@ -84,7 +85,7 @@ func (o *Options) Verify() error { } if o.Scheduler != "" { - valid := isInArray(validSchedulerOptions, o.Scheduler) + valid := slices.Contains(validSchedulerOptions, o.Scheduler) if !valid { return fmt.Errorf(`invalid scheduler option '%s': valid values are %s`, o.Scheduler, @@ -93,7 +94,7 @@ func (o *Options) Verify() error { } if o.Serial != "" { - valid := isInArray(validSerialOptions, o.Serial) + valid := slices.Contains(validSerialOptions, o.Serial) if !valid { return fmt.Errorf(`invalid serial option '%s': valid values are %s`, o.Serial, @@ -102,7 +103,7 @@ func (o *Options) Verify() error { } if o.PrintSizes != "" { - valid := isInArray(validPrintSizeOptions, o.PrintSizes) + valid := slices.Contains(validPrintSizeOptions, o.PrintSizes) if !valid { return fmt.Errorf(`invalid size option '%s': valid values are %s`, o.PrintSizes, @@ -111,7 +112,7 @@ func (o *Options) Verify() error { } if o.PanicStrategy != "" { - valid := isInArray(validPanicStrategyOptions, o.PanicStrategy) + valid := slices.Contains(validPanicStrategyOptions, o.PanicStrategy) if !valid { return fmt.Errorf(`invalid panic option '%s': valid values are %s`, o.PanicStrategy, @@ -120,19 +121,10 @@ func (o *Options) Verify() error { } if o.Opt != "" { - if !isInArray(validOptOptions, o.Opt) { + if !slices.Contains(validOptOptions, o.Opt) { return fmt.Errorf("invalid -opt=%s: valid values are %s", o.Opt, strings.Join(validOptOptions, ", ")) } } return nil } - -func isInArray(arr []string, item string) bool { - for _, i := range arr { - if i == item { - return true - } - } - return false -} diff --git a/compiler/compiler.go b/compiler/compiler.go index 2b3419ed48..ec553e196d 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -168,7 +168,7 @@ type builder struct { dilocals map[*types.Var]llvm.Metadata initInlinedAt llvm.Metadata // fake inlinedAt position initPseudoFuncs map[string]llvm.Metadata // fake "inlined" functions for proper init debug locations - allDeferFuncs []interface{} + allDeferFuncs []any deferFuncs map[*ssa.Function]int deferInvokeFuncs map[string]int deferClosureFuncs map[*ssa.Function]int @@ -2154,13 +2154,10 @@ func (c *compilerContext) maxSliceSize(elementType llvm.Type) uint64 { if elementSize == 0 { elementSize = 1 } - maxSize := maxPointerValue / elementSize - - // len(slice) is an int. Make sure the length remains small enough to fit in - // an int. - if maxSize > maxIntegerValue { - maxSize = maxIntegerValue - } + maxSize := min( + // len(slice) is an int. Make sure the length remains small enough to fit in + // an int. + maxPointerValue/elementSize, maxIntegerValue) return maxSize } diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go index 43754ec1ff..69b1f11653 100644 --- a/compiler/compiler_test.go +++ b/compiler/compiler_test.go @@ -188,9 +188,9 @@ func TestCompilerErrors(t *testing.T) { t.Error(err) } errorsFileString := strings.ReplaceAll(string(errorsFile), "\r\n", "\n") - for _, line := range strings.Split(errorsFileString, "\n") { - if strings.HasPrefix(line, "// ERROR: ") { - expectedErrors = append(expectedErrors, strings.TrimPrefix(line, "// ERROR: ")) + for line := range strings.SplitSeq(errorsFileString, "\n") { + if after, ok := strings.CutPrefix(line, "// ERROR: "); ok { + expectedErrors = append(expectedErrors, after) } } diff --git a/compiler/defer.go b/compiler/defer.go index 666b3f465e..3a91f87677 100644 --- a/compiler/defer.go +++ b/compiler/defer.go @@ -669,8 +669,8 @@ func (b *builder) createRunDefers() { fn := callback.Fn.(*ssa.Function) valueTypes := []llvm.Type{b.uintptrType, b.dataPtrType} params := fn.Signature.Params() - for i := 0; i < params.Len(); i++ { - valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type())) + for v := range params.Variables() { + valueTypes = append(valueTypes, b.getLLVMType(v.Type())) } valueTypes = append(valueTypes, b.dataPtrType) // closure deferredCallType := b.ctx.StructType(valueTypes, false) @@ -695,8 +695,8 @@ func (b *builder) createRunDefers() { //Get signature from call results params := callback.Type().Underlying().(*types.Signature).Params() - for i := 0; i < params.Len(); i++ { - valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type())) + for v := range params.Variables() { + valueTypes = append(valueTypes, b.getLLVMType(v.Type())) } deferredCallType := b.ctx.StructType(valueTypes, false) diff --git a/compiler/func.go b/compiler/func.go index 0af81445c9..665d7ddd09 100644 --- a/compiler/func.go +++ b/compiler/func.go @@ -81,8 +81,8 @@ func (c *compilerContext) getLLVMFunctionType(typ *types.Signature) llvm.Type { paramTypes = append(paramTypes, info.llvmType) } } - for i := 0; i < typ.Params().Len(); i++ { - subType := c.getLLVMType(typ.Params().At(i).Type()) + for v := range typ.Params().Variables() { + subType := c.getLLVMType(v.Type()) for _, info := range c.expandFormalParamType(subType, "", nil) { paramTypes = append(paramTypes, info.llvmType) } diff --git a/compiler/gc.go b/compiler/gc.go index b5246e2187..40785ee7ab 100644 --- a/compiler/gc.go +++ b/compiler/gc.go @@ -5,6 +5,7 @@ package compiler import ( "go/token" + "slices" "golang.org/x/tools/go/ssa" "tinygo.org/x/go-llvm" @@ -88,7 +89,7 @@ func (b *builder) trackValue(value llvm.Value) { return } numElements := typ.StructElementTypesCount() - for i := 0; i < numElements; i++ { + for i := range numElements { subValue := b.CreateExtractValue(value, i, "") b.trackValue(subValue) } @@ -97,7 +98,7 @@ func (b *builder) trackValue(value llvm.Value) { return } numElements := typ.ArrayLength() - for i := 0; i < numElements; i++ { + for i := range numElements { subValue := b.CreateExtractValue(value, i, "") b.trackValue(subValue) } @@ -118,12 +119,7 @@ func typeHasPointers(t llvm.Type) bool { case llvm.PointerTypeKind: return true case llvm.StructTypeKind: - for _, subType := range t.StructElementTypes() { - if typeHasPointers(subType) { - return true - } - } - return false + return slices.ContainsFunc(t.StructElementTypes(), typeHasPointers) case llvm.ArrayTypeKind: if t.ArrayLength() == 0 { return false diff --git a/compiler/goroutine.go b/compiler/goroutine.go index 701797152c..30c8ef2426 100644 --- a/compiler/goroutine.go +++ b/compiler/goroutine.go @@ -414,7 +414,7 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm. // Extract parameters from the state object, and call the function // that's being wrapped. var callParams []llvm.Value - for i := 0; i < numParams; i++ { + for i := range numParams { gep := b.CreateInBoundsGEP(stateStruct, statePtr, []llvm.Value{ llvm.ConstInt(b.ctx.Int32Type(), 0, false), llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false), diff --git a/compiler/inlineasm.go b/compiler/inlineasm.go index 9f62ec4efc..caec63e826 100644 --- a/compiler/inlineasm.go +++ b/compiler/inlineasm.go @@ -146,13 +146,14 @@ func (b *builder) emitSVCall(args []ssa.Value, pos token.Pos) (llvm.Value, error llvmArgs := []llvm.Value{} argTypes := []llvm.Type{} asm := "svc #" + strconv.FormatUint(num, 10) - constraints := "={r0}" + var constraints strings.Builder + constraints.WriteString("={r0}") for i, arg := range args[1:] { arg = arg.(*ssa.MakeInterface).X if i == 0 { - constraints += ",0" + constraints.WriteString(",0") } else { - constraints += ",{r" + strconv.Itoa(i) + "}" + constraints.WriteString(",{r" + strconv.Itoa(i) + "}") } llvmValue := b.getValue(arg, pos) llvmArgs = append(llvmArgs, llvmValue) @@ -161,9 +162,9 @@ func (b *builder) emitSVCall(args []ssa.Value, pos token.Pos) (llvm.Value, error // Implement the ARM calling convention by marking r1-r3 as // clobbered. r0 is used as an output register so doesn't have to be // marked as clobbered. - constraints += ",~{r1},~{r2},~{r3}" + constraints.WriteString(",~{r1},~{r2},~{r3}") fnType := llvm.FunctionType(b.uintptrType, argTypes, false) - target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false) + target := llvm.InlineAsm(fnType, asm, constraints.String(), true, false, 0, false) return b.CreateCall(fnType, target, llvmArgs, ""), nil } @@ -184,13 +185,14 @@ func (b *builder) emitSV64Call(args []ssa.Value, pos token.Pos) (llvm.Value, err llvmArgs := []llvm.Value{} argTypes := []llvm.Type{} asm := "svc #" + strconv.FormatUint(num, 10) - constraints := "={x0}" + var constraints strings.Builder + constraints.WriteString("={x0}") for i, arg := range args[1:] { arg = arg.(*ssa.MakeInterface).X if i == 0 { - constraints += ",0" + constraints.WriteString(",0") } else { - constraints += ",{x" + strconv.Itoa(i) + "}" + constraints.WriteString(",{x" + strconv.Itoa(i) + "}") } llvmValue := b.getValue(arg, pos) llvmArgs = append(llvmArgs, llvmValue) @@ -199,9 +201,9 @@ func (b *builder) emitSV64Call(args []ssa.Value, pos token.Pos) (llvm.Value, err // Implement the ARM64 calling convention by marking x1-x7 as // clobbered. x0 is used as an output register so doesn't have to be // marked as clobbered. - constraints += ",~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7}" + constraints.WriteString(",~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7}") fnType := llvm.FunctionType(b.uintptrType, argTypes, false) - target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false) + target := llvm.InlineAsm(fnType, asm, constraints.String(), true, false, 0, false) return b.CreateCall(fnType, target, llvmArgs, ""), nil } diff --git a/compiler/interface.go b/compiler/interface.go index 136dc26fcb..3908a69d18 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -145,8 +145,8 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { // For a non-interface type, it returns the number of exported methods. // For an interface type, it returns the number of exported and unexported methods. var numMethods int - for i := 0; i < ms.Len(); i++ { - if isInterface || ms.At(i).Obj().Exported() { + for method := range ms.Methods() { + if isInterface || method.Obj().Exported() { numMethods++ } } @@ -193,8 +193,8 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { } // Compute the method set value for types that support methods. var methods []*types.Func - for i := 0; i < ms.Len(); i++ { - methods = append(methods, ms.At(i).Obj().(*types.Func)) + for method := range ms.Methods() { + methods = append(methods, method.Obj().(*types.Func)) } methodSetType := types.NewStruct([]*types.Var{ types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]), @@ -490,10 +490,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { c.getTypeMethodSet(typ), }, typeFields...) } - alignment := c.targetData.TypeAllocSize(c.dataPtrType) - if alignment < 4 { - alignment = 4 - } + alignment := max(c.targetData.TypeAllocSize(c.dataPtrType), 4) globalValue := c.ctx.ConstStruct(typeFields, false) global.SetInitializer(globalValue) if isLocal { @@ -783,12 +780,12 @@ func (c *compilerContext) scanLocalTypes(ssaPkg *ssa.Package) { walk(m, false) case *ssa.Type: mset := c.program.MethodSets.MethodSet(m.Type()) - for i := 0; i < mset.Len(); i++ { - walk(c.program.MethodValue(mset.At(i)), false) + for method := range mset.Methods() { + walk(c.program.MethodValue(method), false) } pmset := c.program.MethodSets.MethodSet(types.NewPointer(m.Type())) - for i := 0; i < pmset.Len(); i++ { - walk(c.program.MethodValue(pmset.At(i)), false) + for method := range pmset.Methods() { + walk(c.program.MethodValue(method), false) } } } @@ -846,8 +843,8 @@ func (c *compilerContext) registerSyntheticLocalTypes(fn *ssa.Function) { } } targs := t.TypeArgs() - for i := 0; i < targs.Len(); i++ { - visit(targs.At(i)) + for t := range targs.Types() { + visit(t) } visit(t.Underlying()) case *types.Pointer: @@ -862,23 +859,23 @@ func (c *compilerContext) registerSyntheticLocalTypes(fn *ssa.Function) { visit(t.Key()) visit(t.Elem()) case *types.Struct: - for i := 0; i < t.NumFields(); i++ { - visit(t.Field(i).Type()) + for field := range t.Fields() { + visit(field.Type()) } case *types.Signature: if p := t.Params(); p != nil { - for i := 0; i < p.Len(); i++ { - visit(p.At(i).Type()) + for v := range p.Variables() { + visit(v.Type()) } } if r := t.Results(); r != nil { - for i := 0; i < r.Len(); i++ { - visit(r.At(i).Type()) + for v := range r.Variables() { + visit(v.Type()) } } case *types.Tuple: - for i := 0; i < t.Len(); i++ { - visit(t.At(i).Type()) + for v := range t.Variables() { + visit(v.Type()) } case *types.Interface: // A synthetic local type can be reachable only through a @@ -887,8 +884,8 @@ func (c *compilerContext) registerSyntheticLocalTypes(fn *ssa.Function) { // the interface's identifier, and the seen map breaks // cycles formed by methods that mention the interface // itself. - for i := 0; i < t.NumMethods(); i++ { - visit(t.Method(i).Type()) + for method := range t.Methods() { + visit(method.Type()) } } } @@ -939,8 +936,7 @@ func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value { // Create method set. var signatures, wrappers []llvm.Value - for i := 0; i < ms.Len(); i++ { - method := ms.At(i) + for method := range ms.Methods() { signatureGlobal := c.getMethodSignature(method.Obj().(*types.Func)) signatures = append(signatures, signatureGlobal) fn := c.program.MethodValue(method) @@ -1189,8 +1185,8 @@ func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value { if llvmFn.IsNil() { sig := instr.Method.Type().(*types.Signature) var paramTuple []*types.Var - for i := 0; i < sig.Params().Len(); i++ { - paramTuple = append(paramTuple, sig.Params().At(i)) + for v := range sig.Params().Variables() { + paramTuple = append(paramTuple, v) } paramTuple = append(paramTuple, types.NewVar(token.NoPos, nil, "$typecode", types.Typ[types.UnsafePointer])) llvmFnType := c.getLLVMFunctionType(types.NewSignature(sig.Recv(), types.NewTuple(paramTuple...), sig.Results(), false)) @@ -1307,34 +1303,38 @@ func methodSignature(method *types.Func) string { // () string // (string, int) (int, error) func signature(sig *types.Signature) string { - s := "" + var s strings.Builder if sig.Params().Len() == 0 { - s += "()" + s.WriteString("()") } else { - s += "(" - for i := 0; i < sig.Params().Len(); i++ { + s.WriteString("(") + i := 0 + for v := range sig.Params().Variables() { if i > 0 { - s += ", " + s.WriteString(", ") } - s += typestring(sig.Params().At(i).Type()) + s.WriteString(typestring(v.Type())) + i++ } - s += ")" + s.WriteString(")") } if sig.Results().Len() == 0 { // keep as-is } else if sig.Results().Len() == 1 { - s += " " + typestring(sig.Results().At(0).Type()) + s.WriteString(" " + typestring(sig.Results().At(0).Type())) } else { - s += " (" - for i := 0; i < sig.Results().Len(); i++ { + s.WriteString(" (") + i := 0 + for v := range sig.Results().Variables() { if i > 0 { - s += ", " + s.WriteString(", ") } - s += typestring(sig.Results().At(i).Type()) + s.WriteString(typestring(v.Type())) + i++ } - s += ")" + s.WriteString(")") } - return s + return s.String() } // typestring returns a stable (human-readable) type string for the given type diff --git a/compiler/llvm.go b/compiler/llvm.go index a7fe725bba..8a31ede086 100644 --- a/compiler/llvm.go +++ b/compiler/llvm.go @@ -206,7 +206,7 @@ func (c *compilerContext) makeGlobalArray(buf []byte, name string, elementType l globalType := llvm.ArrayType(elementType, len(buf)) global := llvm.AddGlobal(c.mod, globalType, name) value := llvm.Undef(globalType) - for i := 0; i < len(buf); i++ { + for i := range buf { ch := uint64(buf[i]) value = c.builder.CreateInsertValue(value, llvm.ConstInt(elementType, ch, false), i, "") } @@ -390,7 +390,7 @@ func (c *compilerContext) buildPointerBitmap( return } elementSize /= ptrAlign - for i := 0; i < len; i++ { + for i := range len { c.buildPointerBitmap( dst, ptrAlign, @@ -417,7 +417,7 @@ func (c *compilerContext) archFamily() string { // features string is not one for an ARM architecture. func (c *compilerContext) isThumb() bool { var isThumb, isNotThumb bool - for _, feature := range strings.Split(c.Features, ",") { + for feature := range strings.SplitSeq(c.Features, ",") { if feature == "+thumb-mode" { isThumb = true } diff --git a/compiler/map.go b/compiler/map.go index fda2cec2c4..4f9ec66ea5 100644 --- a/compiler/map.go +++ b/compiler/map.go @@ -7,6 +7,7 @@ import ( "go/token" "go/types" "golang.org/x/tools/go/ssa" + "strings" "tinygo.org/x/go-llvm" ) @@ -293,14 +294,15 @@ func hashmapCanonicalTypeName(t types.Type) string { } return t.String() case *types.Struct: - s := "struct{" + var s strings.Builder + s.WriteString("struct{") for i := 0; i < t.NumFields(); i++ { if i > 0 { - s += "; " + s.WriteString("; ") } - s += hashmapCanonicalTypeName(t.Field(i).Type()) + s.WriteString(hashmapCanonicalTypeName(t.Field(i).Type())) } - return s + "}" + return s.String() + "}" case *types.Array: return fmt.Sprintf("[%d]%s", t.Len(), hashmapCanonicalTypeName(t.Elem())) } diff --git a/compiler/sizes.go b/compiler/sizes.go index d19d634ce1..4556649c4f 100644 --- a/compiler/sizes.go +++ b/compiler/sizes.go @@ -29,8 +29,7 @@ func (s *stdSizes) Alignof(T types.Type) int64 { // is the largest of the values unsafe.Alignof(x.f) for each // field f of x, but at least 1." max := int64(1) - for i := 0; i < t.NumFields(); i++ { - f := t.Field(i) + for f := range t.Fields() { if a := s.Alignof(f.Type()); a > max { max = a } diff --git a/compiler/symbol.go b/compiler/symbol.go index fec98ce3b4..9076e870de 100644 --- a/compiler/symbol.go +++ b/compiler/symbol.go @@ -8,6 +8,7 @@ import ( "go/ast" "go/token" "go/types" + "slices" "strconv" "strings" @@ -85,8 +86,8 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value) retType = c.getLLVMType(fn.Signature.Results().At(0).Type()) } else { results := make([]llvm.Type, 0, fn.Signature.Results().Len()) - for i := 0; i < fn.Signature.Results().Len(); i++ { - results = append(results, c.getLLVMType(fn.Signature.Results().At(i).Type())) + for v := range fn.Signature.Results().Variables() { + results = append(results, c.getLLVMType(v.Type())) } retType = c.ctx.StructType(results, false) } @@ -389,7 +390,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) { info.wasmName = info.linkName info.exported = true case "//go:interrupt": - if hasUnsafeImport(f.Pkg.Pkg) { + if slices.Contains(f.Pkg.Pkg.Imports(), types.Unsafe) { info.interrupt = true } case "//go:wasm-module": @@ -451,14 +452,14 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) { // This is a slightly looser requirement than what gc uses: gc // requires the file to import "unsafe", not the package as a // whole. - if hasUnsafeImport(f.Pkg.Pkg) { + if slices.Contains(f.Pkg.Pkg.Imports(), types.Unsafe) { info.linkName = parts[2] } case "//go:section": // Only enable go:section when the package imports "unsafe". // go:section also implies go:noinline since inlining could // move the code to a different section than that requested. - if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) { + if len(parts) == 2 && slices.Contains(f.Pkg.Pkg.Imports(), types.Unsafe) { info.section = parts[1] info.inline = inlineNone } @@ -467,7 +468,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) { // runtime functions. // This is somewhat dangerous and thus only imported in packages // that import unsafe. - if hasUnsafeImport(f.Pkg.Pkg) { + if slices.Contains(f.Pkg.Pkg.Imports(), types.Unsafe) { info.nobounds = true } case "//go:noescape": @@ -567,8 +568,8 @@ func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool { hasHostLayout = false // package structs added in go1.23 } } - for i := 0; i < typ.NumFields(); i++ { - ftyp := typ.Field(i).Type() + for field := range typ.Fields() { + ftyp := field.Type() if types.Unalias(ftyp).String() == "structs.HostLayout" { hasHostLayout = true continue @@ -600,8 +601,8 @@ func getParams(sig *types.Signature) []*types.Var { if sig.Recv() != nil { params = append(params, sig.Recv()) } - for i := 0; i < sig.Params().Len(); i++ { - params = append(params, sig.Params().At(i)) + for v := range sig.Params().Variables() { + params = append(params, v) } return params } @@ -704,10 +705,7 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value { llvmGlobal = llvm.AddGlobal(c.mod, llvmType, info.linkName) // Set alignment from the //go:align comment. - alignment := c.targetData.ABITypeAlignment(llvmType) - if info.align > alignment { - alignment = info.align - } + alignment := max(info.align, c.targetData.ABITypeAlignment(llvmType)) if alignment <= 0 || alignment&(alignment-1) != 0 { // Check for power-of-two (or 0). // See: https://stackoverflow.com/a/108360 @@ -781,7 +779,7 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup, c *compilerContext, // This is a slightly looser requirement than what gc uses: gc // requires the file to import "unsafe", not the package as a // whole. - if hasUnsafeImport(g.Pkg.Pkg) { + if slices.Contains(g.Pkg.Pkg.Imports(), types.Unsafe) { info.linkName = parts[2] } } @@ -797,13 +795,3 @@ func getAllMethods(prog *ssa.Program, typ types.Type) []*types.Selection { } return methods } - -// Return true if this package imports "unsafe", false otherwise. -func hasUnsafeImport(pkg *types.Package) bool { - for _, imp := range pkg.Imports() { - if imp == types.Unsafe { - return true - } - } - return false -} diff --git a/compiler/syscall.go b/compiler/syscall.go index 946acdecb0..5172e78380 100644 --- a/compiler/syscall.go +++ b/compiler/syscall.go @@ -26,24 +26,25 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { argTypes := []llvm.Type{b.uintptrType} // Constraints will look something like: // "={rax},0,{rdi},{rsi},{rdx},{r10},{r8},{r9},~{rcx},~{r11}" - constraints := "={rax},0" + var constraints strings.Builder + constraints.WriteString("={rax},0") for i, arg := range call.Args[1:] { - constraints += "," + [...]string{ + constraints.WriteString("," + [...]string{ "{rdi}", "{rsi}", "{rdx}", "{r10}", "{r8}", "{r9}", - }[i] + }[i]) llvmValue := b.getValue(arg, getPos(call)) args = append(args, llvmValue) argTypes = append(argTypes, llvmValue.Type()) } // rcx and r11 are clobbered by the syscall, so make sure they are not used - constraints += ",~{rcx},~{r11}" + constraints.WriteString(",~{rcx},~{r11}") fnType := llvm.FunctionType(b.uintptrType, argTypes, false) - target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel, false) + target := llvm.InlineAsm(fnType, "syscall", constraints.String(), true, false, llvm.InlineAsmDialectIntel, false) return b.CreateCall(fnType, target, args, ""), nil case b.GOARCH == "386" && b.GOOS == "linux": @@ -55,22 +56,23 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { argTypes := []llvm.Type{b.uintptrType} // Constraints will look something like: // "={eax},0,{ebx},{ecx},{edx},{esi},{edi},{ebp}" - constraints := "={eax},0" + var constraints strings.Builder + constraints.WriteString("={eax},0") for i, arg := range call.Args[1:] { - constraints += "," + [...]string{ + constraints.WriteString("," + [...]string{ "{ebx}", "{ecx}", "{edx}", "{esi}", "{edi}", "{ebp}", - }[i] + }[i]) llvmValue := b.getValue(arg, getPos(call)) args = append(args, llvmValue) argTypes = append(argTypes, llvmValue.Type()) } fnType := llvm.FunctionType(b.uintptrType, argTypes, false) - target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel, false) + target := llvm.InlineAsm(fnType, "int 0x80", constraints.String(), true, false, llvm.InlineAsmDialectIntel, false) return b.CreateCall(fnType, target, args, ""), nil case b.GOARCH == "arm" && b.GOOS == "linux": @@ -88,9 +90,10 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { argTypes := []llvm.Type{} // Constraints will look something like: // ={r0},0,{r1},{r2},{r7},~{r3} - constraints := "={r0}" + var constraints strings.Builder + constraints.WriteString("={r0}") for i, arg := range call.Args[1:] { - constraints += "," + [...]string{ + constraints.WriteString("," + [...]string{ "0", // tie to output "{r1}", "{r2}", @@ -98,20 +101,20 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { "{r4}", "{r5}", "{r6}", - }[i] + }[i]) llvmValue := b.getValue(arg, getPos(call)) args = append(args, llvmValue) argTypes = append(argTypes, llvmValue.Type()) } args = append(args, num) argTypes = append(argTypes, b.uintptrType) - constraints += ",{r7}" // syscall number + constraints.WriteString(",{r7}") // syscall number for i := len(call.Args) - 1; i < 4; i++ { // r0-r3 get clobbered after the syscall returns - constraints += ",~{r" + strconv.Itoa(i) + "}" + constraints.WriteString(",~{r" + strconv.Itoa(i) + "}") } fnType := llvm.FunctionType(b.uintptrType, argTypes, false) - target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false) + target := llvm.InlineAsm(fnType, "svc #0", constraints.String(), true, false, 0, false) return b.CreateCall(fnType, target, args, ""), nil case b.GOARCH == "arm64" && b.GOOS == "linux": @@ -120,31 +123,32 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { argTypes := []llvm.Type{} // Constraints will look something like: // ={x0},0,{x1},{x2},{x8},~{x3},~{x4},~{x5},~{x6},~{x7},~{x16},~{x17} - constraints := "={x0}" + var constraints strings.Builder + constraints.WriteString("={x0}") for i, arg := range call.Args[1:] { - constraints += "," + [...]string{ + constraints.WriteString("," + [...]string{ "0", // tie to output "{x1}", "{x2}", "{x3}", "{x4}", "{x5}", - }[i] + }[i]) llvmValue := b.getValue(arg, getPos(call)) args = append(args, llvmValue) argTypes = append(argTypes, llvmValue.Type()) } args = append(args, num) argTypes = append(argTypes, b.uintptrType) - constraints += ",{x8}" // syscall number + constraints.WriteString(",{x8}") // syscall number for i := len(call.Args) - 1; i < 8; i++ { // x0-x7 may get clobbered during the syscall following the aarch64 // calling convention. - constraints += ",~{x" + strconv.Itoa(i) + "}" + constraints.WriteString(",~{x" + strconv.Itoa(i) + "}") } - constraints += ",~{x16},~{x17}" // scratch registers + constraints.WriteString(",~{x16},~{x17}") // scratch registers fnType := llvm.FunctionType(b.uintptrType, argTypes, false) - target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false) + target := llvm.InlineAsm(fnType, "svc #0", constraints.String(), true, false, 0, false) return b.CreateCall(fnType, target, args, ""), nil case (b.GOARCH == "mips" || b.GOARCH == "mipsle") && b.GOOS == "linux": @@ -163,7 +167,8 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { // faster and smaller code. args := []llvm.Value{num} argTypes := []llvm.Type{b.uintptrType} - constraints := "={$2},={$7},0" + var constraints strings.Builder + constraints.WriteString("={$2},={$7},0") syscallParams := call.Args[1:] if len(syscallParams) > 7 { // There is one syscall that uses 7 parameters: sync_file_range. @@ -172,7 +177,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { syscallParams = syscallParams[:7] } for i, arg := range syscallParams { - constraints += "," + [...]string{ + constraints.WriteString("," + [...]string{ "{$4}", // arg1 "{$5}", // arg2 "{$6}", // arg3 @@ -180,7 +185,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { "r", // arg5 on the stack "r", // arg6 on the stack "r", // arg7 on the stack - }[i] + }[i]) llvmValue := b.getValue(arg, getPos(call)) args = append(args, llvmValue) argTypes = append(argTypes, llvmValue.Type()) @@ -221,10 +226,10 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { "addu $$sp, $$sp, 32\n" + ".set at\n" } - constraints += ",~{$3},~{$4},~{$5},~{$6},~{$8},~{$9},~{$10},~{$11},~{$12},~{$13},~{$14},~{$15},~{$24},~{$25},~{hi},~{lo},~{memory}" + constraints.WriteString(",~{$3},~{$4},~{$5},~{$6},~{$8},~{$9},~{$10},~{$11},~{$12},~{$13},~{$14},~{$15},~{$24},~{$25},~{hi},~{lo},~{memory}") returnType := b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType}, false) fnType := llvm.FunctionType(returnType, argTypes, false) - target := llvm.InlineAsm(fnType, asm, constraints, true, true, 0, false) + target := llvm.InlineAsm(fnType, asm, constraints.String(), true, true, 0, false) call := b.CreateCall(fnType, target, args, "") resultCode := b.CreateExtractValue(call, 0, "") // r2 errorFlag := b.CreateExtractValue(call, 1, "") // r7 diff --git a/corpus_test.go b/corpus_test.go index f17a9b9f50..707bbcfd48 100644 --- a/corpus_test.go +++ b/corpus_test.go @@ -59,7 +59,6 @@ func TestCorpus(t *testing.T) { } for _, repo := range repos { - repo := repo name := repo.Repo if repo.Tags != "" { name += "(" + strings.ReplaceAll(repo.Tags, " ", "-") + ")" @@ -132,7 +131,6 @@ func TestCorpus(t *testing.T) { } for _, dir := range repo.Subdirs { - dir := dir t.Run(dir.Pkg, func(t *testing.T) { t.Parallel() diff --git a/diff.go b/diff.go index 87ce86d0e5..13243445a6 100644 --- a/diff.go +++ b/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/errors_test.go b/errors_test.go index 69c372bf28..3df76b332e 100644 --- a/errors_test.go +++ b/errors_test.go @@ -136,7 +136,7 @@ func readErrorMessages(t *testing.T, file string) string { } var errors []string - for _, line := range strings.Split(string(data), "\n") { + for line := range strings.SplitSeq(string(data), "\n") { if strings.HasPrefix(line, "// ERROR: ") { errors = append(errors, strings.TrimRight(line[len("// ERROR: "):], "\r\n")) } diff --git a/interp/compiler.go b/interp/compiler.go index 37faaae541..e909df80bc 100644 --- a/interp/compiler.go +++ b/interp/compiler.go @@ -151,7 +151,7 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function { case llvm.PHI: inst.name = llvmInst.Name() incomingCount := inst.llvmInst.IncomingCount() - for i := 0; i < incomingCount; i++ { + for i := range incomingCount { incomingBB := inst.llvmInst.IncomingBlock(i) incomingValue := inst.llvmInst.IncomingValue(i) inst.operands = append(inst.operands, diff --git a/interp/interp_test.go b/interp/interp_test.go index b5dbccdfde..bfb1ae2be1 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -22,7 +22,6 @@ func TestInterp(t *testing.T) { "alloc", "slicedata", } { - name := name // make local to this closure t.Run(name, func(t *testing.T) { t.Parallel() runTest(t, "testdata/"+name) diff --git a/interp/interpreter.go b/interp/interpreter.go index ea6f678c26..4c8c36fe75 100644 --- a/interp/interpreter.go +++ b/interp/interpreter.go @@ -5,6 +5,7 @@ import ( "fmt" "math" "os" + "slices" "strconv" "strings" "time" @@ -470,7 +471,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent // should be returned. numMethods := int(r.builder.CreateExtractValue(methodSet, 0, "").ZExtValue()) var method llvm.Value - for i := 0; i < numMethods; i++ { + for i := range numMethods { methodSignatureAgg := r.builder.CreateExtractValue(methodSet, 1, "") methodSignature := r.builder.CreateExtractValue(methodSignatureAgg, i, "") if methodSignature == signature { @@ -907,7 +908,7 @@ func (r *runner) interpretICmp(lhs, rhs value, predicate llvm.IntPredicate) bool func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, mem *memoryView, indent string) *Error { numOperands := inst.llvmInst.OperandsCount() operands := make([]llvm.Value, numOperands) - for i := 0; i < numOperands; i++ { + for i := range numOperands { operand := inst.llvmInst.Operand(i) if !operand.IsAInstruction().IsNil() || !operand.IsAArgument().IsNil() { var err error @@ -985,9 +986,9 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me mem.instructions = append(mem.instructions, agg) } result = operands[1] - for i := len(indices) - 1; i >= 0; i-- { + for i, indice := range slices.Backward(indices) { agg := aggregates[i] - result = r.builder.CreateInsertValue(agg, result, int(indices[i]), inst.name+".insertvalue"+strconv.Itoa(i)) + result = r.builder.CreateInsertValue(agg, result, int(indice), inst.name+".insertvalue"+strconv.Itoa(i)) if i != 0 { // don't add last result to mem.instructions as it will be done at the end already mem.instructions = append(mem.instructions, result) } diff --git a/interp/memory.go b/interp/memory.go index ff86240fd4..6ed4ebae4d 100644 --- a/interp/memory.go +++ b/interp/memory.go @@ -18,8 +18,10 @@ import ( "encoding/binary" "errors" "fmt" + "maps" "math" "math/big" + "slices" "strconv" "strings" @@ -80,9 +82,7 @@ func (mv *memoryView) extend(sub memoryView) { if mv.objects == nil && len(sub.objects) != 0 { mv.objects = make(map[uint32]object) } - for key, value := range sub.objects { - mv.objects[key] = value - } + maps.Copy(mv.objects, sub.objects) mv.instructions = append(mv.instructions, sub.instructions...) } @@ -90,8 +90,8 @@ func (mv *memoryView) extend(sub memoryView) { // created in this memoryView. Do not reuse this memoryView. func (mv *memoryView) revert() { // Erase instructions in reverse order. - for i := len(mv.instructions) - 1; i >= 0; i-- { - llvmInst := mv.instructions[i] + for _, llvmInst := range slices.Backward(mv.instructions) { + if llvmInst.IsAInstruction().IsNil() { // The IR builder will try to create constant versions of // instructions whenever possible. If it does this, it's not an @@ -172,7 +172,7 @@ func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) error { continue } numOperands := inst.OperandsCount() - for i := 0; i < numOperands; i++ { + for i := range numOperands { // Using mark '2' (which means read/write access) // because this might be a store instruction. err := mv.markExternal(inst.Operand(i), 2) @@ -215,7 +215,7 @@ func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) error { // need any marking. case llvm.StructTypeKind: numElements := llvmType.StructElementTypesCount() - for i := 0; i < numElements; i++ { + for i := range numElements { element := mv.r.builder.CreateExtractValue(llvmValue, i, "") err := mv.markExternal(element, mark) if err != nil { @@ -224,7 +224,7 @@ func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) error { } case llvm.ArrayTypeKind: numElements := llvmType.ArrayLength() - for i := 0; i < numElements; i++ { + for i := range numElements { element := mv.r.builder.CreateExtractValue(llvmValue, i, "") err := mv.markExternal(element, mark) if err != nil { @@ -366,7 +366,7 @@ func (mv *memoryView) store(v value, p pointerValue) bool { buffer := obj.buffer.asRawValue(mv.r) obj.buffer = buffer v := v.asRawValue(mv.r) - for i := uint32(0); i < valueLen; i++ { + for i := range valueLen { buffer.buf[p.offset()+i] = v.buf[i] } } @@ -392,7 +392,7 @@ type value interface { // literalValue contains simple integer values that don't need to be stored in a // buffer. type literalValue struct { - value interface{} + value any } // Make a literalValue given the number of bits. @@ -1015,7 +1015,7 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) { if err != nil { panic(err) } - for i := uint32(0); i < ptrSize; i++ { + for i := range ptrSize { v.buf[i] = ptr.pointer } } else if !llvmValue.IsAConstantExpr().IsNil() { @@ -1056,7 +1056,7 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) { panic(err) } ptrValue.pointer += totalOffset - for i := uint32(0); i < ptrSize; i++ { + for i := range ptrSize { v.buf[i] = ptrValue.pointer } case llvm.ICmp: @@ -1113,7 +1113,7 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) { } case llvm.StructTypeKind: numElements := llvmType.StructElementTypesCount() - for i := 0; i < numElements; i++ { + for i := range numElements { offset := r.targetData.ElementOffset(llvmType, i) field := rawValue{ buf: v.buf[offset:], @@ -1124,7 +1124,7 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) { numElements := llvmType.ArrayLength() childType := llvmType.ElementType() childTypeSize := r.targetData.TypeAllocSize(childType) - for i := 0; i < numElements; i++ { + for i := range numElements { offset := i * int(childTypeSize) field := rawValue{ buf: v.buf[offset:], diff --git a/main.go b/main.go index f7f2ad9667..62f01e3e3a 100644 --- a/main.go +++ b/main.go @@ -786,15 +786,15 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option } defer func() { daemon.Process.Signal(os.Interrupt) - var stopped uint32 + var stopped atomic.Uint32 go func() { time.Sleep(time.Millisecond * 100) - if atomic.LoadUint32(&stopped) == 0 { + if stopped.Load() == 0 { daemon.Process.Kill() } }() daemon.Wait() - atomic.StoreUint32(&stopped, 1) + stopped.Store(1) }() } @@ -1046,7 +1046,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c func touchSerialPortAt1200bps(port string) (err error) { retryCount := 3 - for i := 0; i < retryCount; i++ { + for range retryCount { // Open port p, e := serial.Open(port, &serial.Mode{BaudRate: 1200}) if e != nil { @@ -1244,7 +1244,7 @@ func findFATMounts(options *compileopts.Options) ([]mountPoint, error) { if err != nil { return nil, fmt.Errorf("could not list mount points: %w", err) } - for _, line := range strings.Split(string(tab), "\n") { + for line := range strings.SplitSeq(string(tab), "\n") { fields := strings.Fields(line) if len(fields) <= 2 { continue @@ -1273,7 +1273,7 @@ func findFATMounts(options *compileopts.Options) ([]mountPoint, error) { } // Extract data to convert to a []mountPoint slice. - for _, line := range strings.Split(out.String(), "\n") { + for line := range strings.SplitSeq(out.String(), "\n") { words := strings.Fields(line) if len(words) < 3 { continue @@ -1685,18 +1685,18 @@ func (m globalValuesFlag) String() string { } func (m globalValuesFlag) Set(value string) error { - equalsIndex := strings.IndexByte(value, '=') - if equalsIndex < 0 { + before, after, ok := strings.Cut(value, "=") + if !ok { return errors.New("expected format pkgpath.Var=value") } - pathAndName := value[:equalsIndex] + pathAndName := before pointIndex := strings.LastIndexByte(pathAndName, '.') if pointIndex < 0 { return errors.New("expected format pkgpath.Var=value") } path := pathAndName[:pointIndex] name := pathAndName[pointIndex+1:] - stringValue := value[equalsIndex+1:] + stringValue := after if m[path] == nil { m[path] = make(map[string]string) } @@ -2054,7 +2054,6 @@ func main() { // This uses an additional semaphore to reduce the memory usage. testSema := make(chan struct{}, cap(options.Semaphore)) for i, pkgName := range explicitPkgNames { - pkgName := pkgName buf := &bufs[i] testSema <- struct{}{} wg.Add(1) diff --git a/main_test.go b/main_test.go index 0da9e5b6b5..4e4b73a4db 100644 --- a/main_test.go +++ b/main_test.go @@ -392,7 +392,7 @@ func emuCheck(t *testing.T, options compileopts.Options) { t.Fatal("failed to load target spec:", err) } if spec.Emulator != "" { - emulatorCommand := strings.SplitN(spec.Emulator, " ", 2)[0] + emulatorCommand, _, _ := strings.Cut(spec.Emulator, " ") _, err := exec.LookPath(emulatorCommand) if err != nil { if errors.Is(err, exec.ErrNotFound) { @@ -481,7 +481,7 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c if err != nil { w := &bytes.Buffer{} diagnostics.CreateDiagnostics(err).WriteTo(w, "") - for _, line := range strings.Split(strings.TrimRight(w.String(), "\n"), "\n") { + for line := range strings.SplitSeq(strings.TrimRight(w.String(), "\n"), "\n") { t.Log(line) } if stdout.Len() != 0 { @@ -539,7 +539,6 @@ func TestWebAssembly(t *testing.T) { {name: "panic-default", target: "wasip1", imports: []string{"wasi_snapshot_preview1.fd_write", "wasi_snapshot_preview1.random_get"}}, {name: "panic-trap", target: "wasm-unknown", panicStrategy: "trap", imports: []string{}}, } { - tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() tmpdir := t.TempDir() @@ -661,7 +660,6 @@ func TestWasmExport(t *testing.T) { } for _, tc := range tests { - tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() @@ -831,7 +829,6 @@ func TestWasmExportJS(t *testing.T) { {name: "c-shared", buildMode: "c-shared"}, } for _, tc := range tests { - tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() // Build the wasm binary. @@ -879,7 +876,6 @@ func TestWasmExit(t *testing.T) { {name: "exit-1-sleep", output: "slept\nexit code: 1\n"}, } for _, tc := range tests { - tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() options := optionsFromTarget("wasm", sema) @@ -954,7 +950,6 @@ func TestTest(t *testing.T) { ) } for _, targ := range targs { - targ := targ t.Run(targ.name, func(t *testing.T) { t.Parallel() diff --git a/src/examples/memstats/memstats.go b/src/examples/memstats/memstats.go index f0224ac0ff..0f6a0d201b 100644 --- a/src/examples/memstats/memstats.go +++ b/src/examples/memstats/memstats.go @@ -25,7 +25,7 @@ func main() { func escapesToHeap() { n := rand.Intn(100) println("Doing ", n, " iterations") - for i := 0; i < n; i++ { + for i := range n { s := make([]byte, i) _ = append(s, 42) } diff --git a/src/examples/test/test.go b/src/examples/test/test.go index 7a9bb78197..1d3923bb23 100644 --- a/src/examples/test/test.go +++ b/src/examples/test/test.go @@ -70,7 +70,7 @@ func main() { printItf(Number(3)) s := Stringer(thing) println("Stringer.String():", s.String()) - var itf interface{} = s + var itf any = s println("Stringer.(*Thing).String():", itf.(Stringer).String()) // unusual calls @@ -124,7 +124,7 @@ func strlen(s string) int { return len(s) } -func printItf(val interface{}) { +func printItf(val any) { switch val := val.(type) { case Doubler: println("is Doubler:", val.Double()) diff --git a/src/internal/bytealg/bytealg.go b/src/internal/bytealg/bytealg.go index 33ece2bbae..25e81133d5 100644 --- a/src/internal/bytealg/bytealg.go +++ b/src/internal/bytealg/bytealg.go @@ -45,11 +45,8 @@ func Compare(a, b []byte) int { // This function was copied from the Go 1.23 source tree (with runtime_cmpstring // manually inlined). func CompareString(a, b string) int { - l := len(a) - if len(b) < l { - l = len(b) - } - for i := 0; i < l; i++ { + l := min(len(b), len(a)) + for i := range l { c1, c2 := a[i], b[i] if c1 < c2 { return -1 @@ -170,7 +167,7 @@ const PrimeRK = 16777619 // This function was removed in Go 1.22. func HashStrBytes(sep []byte) (uint32, uint32) { hash := uint32(0) - for i := 0; i < len(sep); i++ { + for i := range sep { hash = hash*PrimeRK + uint32(sep[i]) } var pow, sq uint32 = 1, PrimeRK @@ -249,7 +246,7 @@ func IndexRabinKarpBytes(s, sep []byte) int { hashsep, pow := HashStrBytes(sep) n := len(sep) var h uint32 - for i := 0; i < n; i++ { + for i := range n { h = h*PrimeRK + uint32(s[i]) } if h == hashsep && Equal(s[:n], sep) { @@ -276,7 +273,7 @@ func IndexRabinKarp[T string | []byte](s, sep T) int { hashss, pow := HashStr(sep) n := len(sep) var h uint32 - for i := 0; i < n; i++ { + for i := range n { h = h*PrimeRK + uint32(s[i]) } if h == hashss && string(s[:n]) == string(sep) { diff --git a/src/internal/cm/case.go b/src/internal/cm/case.go index 2ca7c28da9..a7cca622a8 100644 --- a/src/internal/cm/case.go +++ b/src/internal/cm/case.go @@ -12,8 +12,8 @@ func CaseUnmarshaler[T ~uint8 | ~uint16 | ~uint32](cases []string) func(v *T, te return &emptyTextError{} } s := string(text) - for i := 0; i < len(cases); i++ { - if cases[i] == s { + for i, c := range cases { + if c == s { *v = T(i) return nil } diff --git a/src/machine/usb/cdc/ring_test.go b/src/machine/usb/cdc/ring_test.go index e79581a5b4..4abf3df226 100644 --- a/src/machine/usb/cdc/ring_test.go +++ b/src/machine/usb/cdc/ring_test.go @@ -268,7 +268,7 @@ func TestRing512_PutOversize(t *testing.T) { func TestRing512_MultiplePutPeekDiscard(t *testing.T) { var r ring512 - for i := 0; i < 2000; i++ { + for i := range 2000 { msg := []byte(fmt.Sprintf("msg%04d", i)) if !r.Put(msg) { t.Fatalf("Put failed at iteration %d, Free=%d, Used=%d", i, r.Free(), r.Used()) @@ -290,7 +290,7 @@ func TestRing512_HeadTailOverflow(t *testing.T) { t.Fatalf("Used=%d Free=%d, want 0/512", r.Used(), r.Free()) } - for i := 0; i < 300; i++ { + for i := range 300 { data := []byte{byte(i), byte(i + 1), byte(i + 2)} if !r.Put(data) { t.Fatalf("Put failed at iter %d (head=%d tail=%d)", i, r.head.Load(), r.tail.Load()) @@ -370,7 +370,7 @@ func TestRing512_PeekTotalEqualsUsed(t *testing.T) { // --- Concurrent SPSC Test --- func TestRing512_SPSC(t *testing.T) { - for trial := 0; trial < 20; trial++ { + for trial := range 20 { var r ring512 const totalBytes = 1 << 18 produced := make([]byte, totalBytes) @@ -431,7 +431,7 @@ func TestRing512_SPSCSmallChunks(t *testing.T) { go func() { defer wg.Done() - for i := 0; i < totalBytes; i++ { + for i := range totalBytes { for !r.Put([]byte{byte(i)}) { } } @@ -494,10 +494,7 @@ func FuzzRing512(f *testing.F) { switch op { case 0: // Put - size := int(arg) - if size > 512 { - size = 512 - } + size := min(int(arg), 512) data := make([]byte, size) for j := range data { data[j] = byte(j) diff --git a/src/sync/cond_test.go b/src/sync/cond_test.go index 6303ab9692..1d636a0af4 100644 --- a/src/sync/cond_test.go +++ b/src/sync/cond_test.go @@ -15,21 +15,21 @@ func TestCondSignal(t *testing.T) { cond.L.Lock() // Start a goroutine to signal us once we wait. - var signaled uint32 + var signaled atomic.Uint32 go func() { // Wait for the test goroutine to wait. cond.L.Lock() defer cond.L.Unlock() // Send a signal to the test goroutine. - atomic.StoreUint32(&signaled, 1) + signaled.Store(1) cond.Signal() }() // Wait for a signal. // This will unlock the mutex, and allow the spawned goroutine to run. cond.Wait() - if atomic.LoadUint32(&signaled) == 0 { + if signaled.Load() == 0 { t.Error("wait returned before a signal was sent") } } @@ -44,7 +44,7 @@ func TestCondBroadcast(t *testing.T) { // Start goroutines to wait for the broadcast. var wg sync.WaitGroup const n = 5 - for i := 0; i < n; i++ { + for range n { wg.Add(1) mu.RLock() go func() { diff --git a/src/sync/mutex_test.go b/src/sync/mutex_test.go index deeb151e4a..f94d9fc597 100644 --- a/src/sync/mutex_test.go +++ b/src/sync/mutex_test.go @@ -14,7 +14,7 @@ type mutex interface { } func HammerMutex(m mutex, loops int, cdone chan bool) { - for i := 0; i < loops; i++ { + for i := range loops { if i%3 == 0 { if m.TryLock() { m.Unlock() @@ -41,10 +41,10 @@ func TestMutex(t *testing.T) { m.Unlock() c := make(chan bool) - for i := 0; i < 10; i++ { + for range 10 { go HammerMutex(m, 1000, c) } - for i := 0; i < 10; i++ { + for range 10 { <-c } } @@ -54,7 +54,7 @@ func TestMutexUncontended(t *testing.T) { var mu sync.Mutex // Lock and unlock the mutex a few times. - for i := 0; i < 3; i++ { + for range 3 { mu.Lock() mu.Unlock() } @@ -69,7 +69,7 @@ func TestMutexConcurrent(t *testing.T) { var fail atomic.Uint32 const n = 10 - for i := 0; i < n; i++ { + for i := range n { j := i go func() { // Delay a bit. @@ -129,12 +129,12 @@ func TestRWMutexUncontended(t *testing.T) { // Acquire several read locks. const n = 5 - for i := 0; i < n; i++ { + for range n { mu.RLock() } // Release all of the read locks. - for i := 0; i < n; i++ { + for range n { mu.RUnlock() } @@ -150,31 +150,31 @@ func TestRWMutexWriteToRead(t *testing.T) { mu.Lock() const n = 3 - var readAcquires uint32 - var completed uint32 - var unlocked uint32 + var readAcquires atomic.Uint32 + var completed atomic.Uint32 + var unlocked atomic.Uint32 var bad uint32 - for i := 0; i < n; i++ { + for range n { go func() { // Acquire a read lock. mu.RLock() // Verify that the write lock is supposed to be released by now. - if atomic.LoadUint32(&unlocked) == 0 { + if unlocked.Load() == 0 { // The write lock is still being held. atomic.AddUint32(&bad, 1) } // Add ourselves to the read lock counter. - atomic.AddUint32(&readAcquires, 1) + readAcquires.Add(1) // Wait for everything to hold the read lock simultaneously. - for atomic.LoadUint32(&readAcquires) < n { + for readAcquires.Load() < n { runtime.Gosched() } // Notify of completion. - atomic.AddUint32(&completed, 1) + completed.Add(1) // Release the read lock. mu.RUnlock() @@ -182,16 +182,16 @@ func TestRWMutexWriteToRead(t *testing.T) { } // Wait a bit for the goroutines to block. - for i := 0; i < 3*n; i++ { + for range 3 * n { runtime.Gosched() } // Release the write lock so that the goroutines acquire read locks. - atomic.StoreUint32(&unlocked, 1) + unlocked.Store(1) mu.Unlock() // Wait for everything to complete. - for atomic.LoadUint32(&completed) < n { + for completed.Load() < n { runtime.Gosched() } @@ -209,7 +209,7 @@ func TestRWMutexReadToWrite(t *testing.T) { const n = 3 var mu sync.RWMutex var readers uint32 - for i := 0; i < n; i++ { + for range n { mu.RLock() readers++ } @@ -230,7 +230,7 @@ func TestRWMutexReadToWrite(t *testing.T) { }() // Release the read locks. - for i := 0; i < n; i++ { + for range n { runtime.Gosched() atomic.AddUint32(&readers, ^uint32(0)) mu.RUnlock() @@ -261,10 +261,10 @@ func TestRWMutex(t *testing.T) { m.Unlock() c := make(chan bool) - for i := 0; i < 10; i++ { + for range 10 { go HammerMutex(m, 1000, c) } - for i := 0; i < 10; i++ { + for range 10 { <-c } } diff --git a/src/sync/pool_test.go b/src/sync/pool_test.go index f73691def7..59779caa1a 100644 --- a/src/sync/pool_test.go +++ b/src/sync/pool_test.go @@ -11,7 +11,7 @@ type testItem struct { func TestPool(t *testing.T) { p := sync.Pool{ - New: func() interface{} { + New: func() any { return &testItem{} }, } diff --git a/src/sync/waitgroup_test.go b/src/sync/waitgroup_test.go index a808f7e11d..9a7ee2f4a7 100644 --- a/src/sync/waitgroup_test.go +++ b/src/sync/waitgroup_test.go @@ -27,7 +27,7 @@ func TestWaitGroup(t *testing.T) { const n = 5 var wg sync.WaitGroup wg.Add(n) - for i := 0; i < n; i++ { + for range n { go wg.Done() } diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go index fadb3b5959..b942d25891 100644 --- a/src/testing/benchmark.go +++ b/src/testing/benchmark.go @@ -170,20 +170,6 @@ func (b *B) runN(n int) { b.StopTimer() } -func min(x, y int64) int64 { - if x > y { - return y - } - return x -} - -func max(x, y int64) int64 { - if x < y { - return y - } - return x -} - // run1 runs the first iteration of benchFunc. It reports whether more // iterations of this benchmarks should be run. func (b *B) run1() bool { diff --git a/src/testing/fuzz.go b/src/testing/fuzz.go index b6eaad409f..6b5cdbd94b 100644 --- a/src/testing/fuzz.go +++ b/src/testing/fuzz.go @@ -53,7 +53,7 @@ type corpusEntry = struct { Parent string Path string Data []byte - Values []interface{} + Values []any Generation int IsSeed bool } @@ -61,8 +61,8 @@ type corpusEntry = struct { // Add will add the arguments to the seed corpus for the fuzz test. This will be // a no-op if called after or within the fuzz target, and args must match the // arguments for the fuzz target. -func (f *F) Add(args ...interface{}) { - var values []interface{} +func (f *F) Add(args ...any) { + var values []any for i := range args { if t := reflect.TypeOf(args[i]); !supportedTypes[t] { panic(fmt.Sprintf("testing: unsupported type to Add %v", t)) @@ -74,23 +74,23 @@ func (f *F) Add(args ...interface{}) { // supportedTypes represents all of the supported types which can be fuzzed. var supportedTypes = map[reflect.Type]bool{ - reflect.TypeOf(([]byte)("")): true, - reflect.TypeOf((string)("")): true, + reflect.TypeFor[[]byte](): true, + reflect.TypeFor[string](): true, reflect.TypeOf((bool)(false)): true, - reflect.TypeOf((byte)(0)): true, - reflect.TypeOf((rune)(0)): true, - reflect.TypeOf((float32)(0)): true, - reflect.TypeOf((float64)(0)): true, - reflect.TypeOf((int)(0)): true, - reflect.TypeOf((int8)(0)): true, - reflect.TypeOf((int16)(0)): true, - reflect.TypeOf((int32)(0)): true, - reflect.TypeOf((int64)(0)): true, - reflect.TypeOf((uint)(0)): true, - reflect.TypeOf((uint8)(0)): true, - reflect.TypeOf((uint16)(0)): true, - reflect.TypeOf((uint32)(0)): true, - reflect.TypeOf((uint64)(0)): true, + reflect.TypeFor[byte](): true, + reflect.TypeFor[rune](): true, + reflect.TypeFor[float32](): true, + reflect.TypeFor[float64](): true, + reflect.TypeFor[int](): true, + reflect.TypeFor[int8](): true, + reflect.TypeFor[int16](): true, + reflect.TypeFor[int32](): true, + reflect.TypeFor[int64](): true, + reflect.TypeFor[uint](): true, + reflect.TypeFor[uint8](): true, + reflect.TypeFor[uint16](): true, + reflect.TypeFor[uint32](): true, + reflect.TypeFor[uint64](): true, } // Fuzz runs the fuzz function, ff, for fuzz testing. If ff fails for a set of @@ -119,7 +119,7 @@ var supportedTypes = map[reflect.Type]bool{ // When fuzzing, F.Fuzz does not return until a problem is found, time runs out // (set with -fuzztime), or the test process is interrupted by a signal. F.Fuzz // should be called exactly once, unless F.Skip or F.Fail is called beforehand. -func (f *F) Fuzz(ff interface{}) { +func (f *F) Fuzz(ff any) { f.failed = true f.result.N = 0 f.result.T = 0 diff --git a/src/testing/testing.go b/src/testing/testing.go index 66cf3d5713..5a28a87b3f 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -137,7 +137,7 @@ func Testing() bool { // flushToParent writes c.output to the parent after first writing the header // with the given format and arguments. -func (c *common) flushToParent(testName, format string, args ...interface{}) { +func (c *common) flushToParent(testName, format string, args ...any) { if c.parent == nil { // The fake top-level test doesn't want a FAIL or PASS banner. // Not quite sure how this works upstream. @@ -157,21 +157,21 @@ func fmtDuration(d time.Duration) string { type TB interface { Cleanup(func()) Context() context.Context - Error(args ...interface{}) - Errorf(format string, args ...interface{}) + Error(args ...any) + Errorf(format string, args ...any) Fail() FailNow() Failed() bool - Fatal(args ...interface{}) - Fatalf(format string, args ...interface{}) + Fatal(args ...any) + Fatalf(format string, args ...any) Helper() - Log(args ...interface{}) - Logf(format string, args ...interface{}) + Log(args ...any) + Logf(format string, args ...any) Name() string Setenv(key, value string) - Skip(args ...interface{}) + Skip(args ...any) SkipNow() - Skipf(format string, args ...interface{}) + Skipf(format string, args ...any) Skipped() bool TempDir() string } @@ -238,47 +238,47 @@ func (c *common) log(s string) { // and records the text in the error log. For tests, the text will be printed only if // the test fails or the -test.v flag is set. For benchmarks, the text is always // printed to avoid having performance depend on the value of the -test.v flag. -func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) } +func (c *common) Log(args ...any) { c.log(fmt.Sprintln(args...)) } // Logf formats its arguments according to the format, analogous to Printf, and // records the text in the error log. A final newline is added if not provided. For // tests, the text will be printed only if the test fails or the -test.v flag is // set. For benchmarks, the text is always printed to avoid having performance // depend on the value of the -test.v flag. -func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) } +func (c *common) Logf(format string, args ...any) { c.log(fmt.Sprintf(format, args...)) } // Error is equivalent to Log followed by Fail. -func (c *common) Error(args ...interface{}) { +func (c *common) Error(args ...any) { c.log(fmt.Sprintln(args...)) c.Fail() } // Errorf is equivalent to Logf followed by Fail. -func (c *common) Errorf(format string, args ...interface{}) { +func (c *common) Errorf(format string, args ...any) { c.log(fmt.Sprintf(format, args...)) c.Fail() } // Fatal is equivalent to Log followed by FailNow. -func (c *common) Fatal(args ...interface{}) { +func (c *common) Fatal(args ...any) { c.log(fmt.Sprintln(args...)) c.FailNow() } // Fatalf is equivalent to Logf followed by FailNow. -func (c *common) Fatalf(format string, args ...interface{}) { +func (c *common) Fatalf(format string, args ...any) { c.log(fmt.Sprintf(format, args...)) c.FailNow() } // Skip is equivalent to Log followed by SkipNow. -func (c *common) Skip(args ...interface{}) { +func (c *common) Skip(args ...any) { c.log(fmt.Sprintln(args...)) c.SkipNow() } // Skipf is equivalent to Logf followed by SkipNow. -func (c *common) Skipf(format string, args ...interface{}) { +func (c *common) Skipf(format string, args ...any) { c.log(fmt.Sprintf(format, args...)) c.SkipNow() } @@ -672,7 +672,7 @@ func (t *T) report() { // Not implemented. func AllocsPerRun(runs int, f func()) (avg float64) { f() - for i := 0; i < runs; i++ { + for range runs { f() } return 0 @@ -688,7 +688,7 @@ type InternalExample struct { // MainStart is meant for use by tests generated by 'go test'. // It is not meant to be called directly and is not subject to the Go 1 compatibility document. // It may change signature from release to release. -func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M { +func MainStart(deps any, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M { Init() return &M{ Tests: tests, diff --git a/src/unique/handle.go b/src/unique/handle.go index 67c925d2de..59c6ec9163 100644 --- a/src/unique/handle.go +++ b/src/unique/handle.go @@ -71,4 +71,4 @@ func Make[T comparable](value T) Handle[T] { } //go:linkname decomposeInterface runtime.decomposeInterface -func decomposeInterface(i interface{}) (unsafe.Pointer, unsafe.Pointer) +func decomposeInterface(i any) (unsafe.Pointer, unsafe.Pointer) diff --git a/transform/interface-lowering.go b/transform/interface-lowering.go index eb954e1d03..6e5af1559d 100644 --- a/transform/interface-lowering.go +++ b/transform/interface-lowering.go @@ -150,11 +150,11 @@ func (p *lowerInterfacesPass) run() error { // Collect all type codes. for global := p.mod.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) { - if strings.HasPrefix(global.Name(), "reflect/types.type:") { + if after, ok := strings.CutPrefix(global.Name(), "reflect/types.type:"); ok { // Retrieve Go type information based on an opaque global variable. // Only the name of the global is relevant, the object itself is // discarded afterwards. - name := strings.TrimPrefix(global.Name(), "reflect/types.type:") + name := after if _, ok := p.types[name]; !ok { t := &typeInfo{ name: name, @@ -463,7 +463,7 @@ func (p *lowerInterfacesPass) addTypeMethods(t *typeInfo, methodSet llvm.Value) signatures := p.builder.CreateExtractValue(set, 1, "") wrappers := p.builder.CreateExtractValue(set, 2, "") numMethods := signatures.Type().ArrayLength() - for i := 0; i < numMethods; i++ { + for i := range numMethods { signatureGlobal := p.builder.CreateExtractValue(signatures, i, "") function := p.builder.CreateExtractValue(wrappers, i, "") function = stripPointerCasts(function) // strip bitcasts @@ -489,7 +489,7 @@ func (p *lowerInterfacesPass) addInterface(methodsString string) { signatures: make(map[string]*signatureInfo), } p.interfaces[methodsString] = t - for _, method := range strings.Split(methodsString, "; ") { + for method := range strings.SplitSeq(methodsString, "; ") { signature := p.getSignature(method) signature.interfaces = append(signature.interfaces, t) t.signatures[method] = signature @@ -683,7 +683,7 @@ func (p *lowerInterfacesPass) extractMethodSigs(field llvm.Value) []string { methodArray := p.builder.CreateExtractValue(field, 1, "") n := methodArray.Type().ArrayLength() sigs := make([]string, 0, n) - for j := 0; j < n; j++ { + for j := range n { sig := p.builder.CreateExtractValue(methodArray, j, "") sig = stripPointerCasts(sig) sigs = append(sigs, sig.Name()) @@ -727,7 +727,7 @@ func (p *lowerInterfacesPass) filterMethodSet(field llvm.Value, keepSigs map[str } entries := make([]methodEntry, numMethods) nameSet := make(map[string]struct{}, numMethods) - for j := 0; j < numMethods; j++ { + for j := range numMethods { sig := p.builder.CreateExtractValue(methodArray, j, "") stripped := stripPointerCasts(sig) name := stripped.Name() diff --git a/transform/llvm.go b/transform/llvm.go index 045bb050f3..8bb3749a6c 100644 --- a/transform/llvm.go +++ b/transform/llvm.go @@ -34,7 +34,7 @@ func hasUses(value llvm.Value) bool { // contents, and returns the global and initializer type. // Note that it is left with the default linkage etc., you should set // linkage/constant/etc properties yourself. -func makeGlobalArray(mod llvm.Module, bufItf interface{}, name string, elementType llvm.Type) (llvm.Type, llvm.Value) { +func makeGlobalArray(mod llvm.Module, bufItf any, name string, elementType llvm.Type) (llvm.Type, llvm.Value) { buf := reflect.ValueOf(bufItf) var values []llvm.Value for i := 0; i < buf.Len(); i++ { @@ -64,7 +64,7 @@ func getGlobalBytes(global llvm.Value, builder llvm.Builder) []byte { // replaceGlobalByteWithArray replaces a global integer type in the module with // an integer array, using a GEP to make the types match. It is a convenience // function used for creating reflection sidetables, for example. -func replaceGlobalIntWithArray(mod llvm.Module, name string, buf interface{}) llvm.Value { +func replaceGlobalIntWithArray(mod llvm.Module, name string, buf any) llvm.Value { oldGlobal := mod.NamedGlobal(name) globalType, global := makeGlobalArray(mod, buf, name+".tmp", oldGlobal.GlobalValueType()) gep := llvm.ConstGEP(globalType, global, []llvm.Value{