diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index 0d3c8b8e3e5e0f..4b7012e6c45e9f 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -2468,8 +2468,8 @@ func TestInstantiateErrors(t *testing.T) { t.Fatalf("Instantiate(%v, %v) returned nil error, want non-nil", T, test.targs) } - var argErr *ArgumentError - if !errors.As(err, &argErr) { + argErr, ok := errors.AsType[*ArgumentError](err) + if !ok { t.Fatalf("Instantiate(%v, %v): error is not an *ArgumentError", T, test.targs) } @@ -2484,8 +2484,8 @@ func TestArgumentErrorUnwrapping(t *testing.T) { Index: 1, Err: Error{Msg: "test"}, } - var e Error - if !errors.As(err, &e) { + e, ok := errors.AsType[Error](err) + if !ok { t.Fatalf("error %v does not wrap types.Error", err) } if e.Msg != "test" { diff --git a/src/cmd/go/internal/base/path.go b/src/cmd/go/internal/base/path.go index 5bb7bc3bde63e2..a7577f62e76898 100644 --- a/src/cmd/go/internal/base/path.go +++ b/src/cmd/go/internal/base/path.go @@ -55,8 +55,7 @@ func sameFile(path1, path2 string) bool { // ShortPathError rewrites the path in err using base.ShortPath, if err is a wrapped PathError. func ShortPathError(err error) error { - var pe *fs.PathError - if errors.As(err, &pe) { + if pe, ok := errors.AsType[*fs.PathError](err); ok { pe.Path = ShortPath(pe.Path) } return err diff --git a/src/cmd/go/internal/doc/pkgsite.go b/src/cmd/go/internal/doc/pkgsite.go index 06289ac4fc9a8a..c173167b6329a4 100644 --- a/src/cmd/go/internal/doc/pkgsite.go +++ b/src/cmd/go/internal/doc/pkgsite.go @@ -81,8 +81,7 @@ func doPkgsite(urlPath, fragment string) error { cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - var ee *exec.ExitError - if errors.As(err, &ee) { + if ee, ok := errors.AsType[*exec.ExitError](err); ok { // Exit with the same exit status as pkgsite to avoid // printing of "exit status" error messages. // Any relevant messages have already been printed diff --git a/src/cmd/go/internal/fmtcmd/fmt.go b/src/cmd/go/internal/fmtcmd/fmt.go index 62b22f6bcfa407..83fba9661a66fc 100644 --- a/src/cmd/go/internal/fmtcmd/fmt.go +++ b/src/cmd/go/internal/fmtcmd/fmt.go @@ -68,11 +68,10 @@ func runFmt(ctx context.Context, cmd *base.Command, args []string) { continue } if pkg.Error != nil { - var nogo *load.NoGoError - var embed *load.EmbedError - if (errors.As(pkg.Error, &nogo) || errors.As(pkg.Error, &embed)) && len(pkg.InternalAllGoFiles()) > 0 { - // Skip this error, as we will format - // all files regardless. + if _, ok := errors.AsType[*load.NoGoError](pkg.Error); ok { + // Skip this error, as we will format all files regardless. + } else if _, ok := errors.AsType[*load.EmbedError](pkg.Error); ok && len(pkg.InternalAllGoFiles()) > 0 { + // Skip this error, as we will format all files regardless. } else { base.Errorf("%v", pkg.Error) continue diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 1f791546f90088..4d536cc4b89f0f 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -290,8 +290,8 @@ func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportSta // Replace (possibly wrapped) *build.NoGoError with *load.NoGoError. // The latter is more specific about the cause. - var nogoErr *build.NoGoError - if errors.As(err, &nogoErr) { + nogoErr, ok := errors.AsType[*build.NoGoError](err) + if ok { if p.Dir == "" && nogoErr.Dir != "" { p.Dir = nogoErr.Dir } diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 25dbf3972fd465..79b54be3ca5284 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -1294,15 +1294,13 @@ func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPack continue } - var ( - importMissing *modload.ImportMissingError - ambiguous *modload.AmbiguousImportError - ) - if !errors.As(err, &importMissing) && !errors.As(err, &ambiguous) { - // The package, which is a dependency of something we care about, has some - // problem that we can't resolve with a version change. - // Leave the error for the final LoadPackages call. - continue + if _, ok := errors.AsType[*modload.ImportMissingError](err); !ok { + if _, ok := errors.AsType[*modload.AmbiguousImportError](err); !ok { + // The package, which is a dependency of something we care about, has some + // problem that we can't resolve with a version change. + // Leave the error for the final LoadPackages call. + continue + } } path := pkgPath @@ -1674,7 +1672,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin } base.SetExitStatus(1) - if ambiguousErr := (*modload.AmbiguousImportError)(nil); errors.As(err, &ambiguousErr) { + if ambiguousErr, ok := errors.AsType[*modload.AmbiguousImportError](err); ok { for _, m := range ambiguousErr.Modules { relevantMods[m] |= hasPkg } @@ -1717,7 +1715,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin i := i r.work.Add(func() { err := modload.CheckRetractions(ctx, retractions[i].m) - if retractErr := (*modload.ModuleRetractedError)(nil); errors.As(err, &retractErr) { + if _, ok := errors.AsType[*modload.ModuleRetractedError](err); ok { retractions[i].message = err.Error() } }) @@ -1994,8 +1992,8 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi toolchain.SwitchOrFatal(ctx, err) } - var constraint *modload.ConstraintError - if !errors.As(err, &constraint) { + constraint, ok := errors.AsType[*modload.ConstraintError](err) + if !ok { base.Fatal(err) } @@ -2066,8 +2064,11 @@ func reqsFromGoMod(f *modfile.File) []module.Version { // does not exist at the requested version, either because the module does not // exist at all or because it does not include that specific version. func isNoSuchModuleVersion(err error) bool { - var noMatch *modload.NoMatchingVersionError - return errors.Is(err, os.ErrNotExist) || errors.As(err, &noMatch) + if errors.Is(err, os.ErrNotExist) { + return true + } + _, ok := errors.AsType[*modload.NoMatchingVersionError](err) + return ok } // isNoSuchPackageVersion reports whether err indicates that the requested @@ -2075,8 +2076,11 @@ func isNoSuchModuleVersion(err error) bool { // that could contain it exists at that version, or because every such module // that does exist does not actually contain the package. func isNoSuchPackageVersion(err error) bool { - var noPackage *modload.PackageNotInModuleError - return isNoSuchModuleVersion(err) || errors.As(err, &noPackage) + if isNoSuchModuleVersion(err) { + return true + } + _, ok := errors.AsType[*modload.PackageNotInModuleError](err) + return ok } // workspace represents the set of modules in a workspace. diff --git a/src/cmd/go/internal/modget/query.go b/src/cmd/go/internal/modget/query.go index 05872d52ec4e04..a7ea8633f2d545 100644 --- a/src/cmd/go/internal/modget/query.go +++ b/src/cmd/go/internal/modget/query.go @@ -283,7 +283,7 @@ func reportError(q *query, err error) { // If err already mentions all of the relevant parts of q, just log err to // reduce stutter. Otherwise, log both q and err. // - // TODO(bcmills): Use errors.As to unpack these errors instead of parsing + // TODO(bcmills): Use errors.AsType to unpack these errors instead of parsing // strings with regular expressions. if !utf8.ValidString(q.pattern) || !utf8.ValidString(q.version) { diff --git a/src/cmd/go/internal/modload/build.go b/src/cmd/go/internal/modload/build.go index 6e30afd5247b36..568019f8ff1c87 100644 --- a/src/cmd/go/internal/modload/build.go +++ b/src/cmd/go/internal/modload/build.go @@ -129,11 +129,10 @@ func addUpdate(ctx context.Context, m *modinfo.ModulePublic) { } info, err := Query(ctx, m.Path, "upgrade", m.Version, CheckAllowed) - var noVersionErr *NoMatchingVersionError - if errors.Is(err, ErrDisallowed) || + if _, ok := errors.AsType[*NoMatchingVersionError](err); ok || errors.Is(err, fs.ErrNotExist) || - errors.As(err, &noVersionErr) { - // Ignore "not found" and "no matching version" errors. + errors.Is(err, ErrDisallowed) { + // Ignore "no matching version" and "not found" errors. // This means the proxy has no matching version or no versions at all. // // Ignore "disallowed" errors. This means the current version is @@ -238,10 +237,10 @@ func addRetraction(ctx context.Context, m *modinfo.ModulePublic) { } err := CheckRetractions(ctx, module.Version{Path: m.Path, Version: m.Version}) - var noVersionErr *NoMatchingVersionError - var retractErr *ModuleRetractedError - if err == nil || errors.Is(err, fs.ErrNotExist) || errors.As(err, &noVersionErr) { - // Ignore "not found" and "no matching version" errors. + if err == nil { + return + } else if _, ok := errors.AsType[*NoMatchingVersionError](err); ok || errors.Is(err, fs.ErrNotExist) { + // Ignore "no matching version" and "not found" errors. // This means the proxy has no matching version or no versions at all. // // We should report other errors though. An attacker that controls the @@ -250,7 +249,7 @@ func addRetraction(ctx context.Context, m *modinfo.ModulePublic) { // hide versions, since the "list" and "latest" endpoints are not // authenticated. return - } else if errors.As(err, &retractErr) { + } else if retractErr, ok := errors.AsType[*ModuleRetractedError](err); ok { if len(retractErr.Rationale) == 0 { m.Retracted = []string{"retracted by module author"} } else { @@ -265,9 +264,8 @@ func addRetraction(ctx context.Context, m *modinfo.ModulePublic) { // author. m.Error is set if there's an error loading deprecation information. func addDeprecation(ctx context.Context, m *modinfo.ModulePublic) { deprecation, err := CheckDeprecation(ctx, module.Version{Path: m.Path, Version: m.Version}) - var noVersionErr *NoMatchingVersionError - if errors.Is(err, fs.ErrNotExist) || errors.As(err, &noVersionErr) { - // Ignore "not found" and "no matching version" errors. + if _, ok := errors.AsType[*NoMatchingVersionError](err); ok || errors.Is(err, fs.ErrNotExist) { + // Ignore "no matching version" and "not found" errors. // This means the proxy has no matching version or no versions at all. // // We should report other errors though. An attacker that controls the diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go index 2ba04f707b5472..0b2264daa6591c 100644 --- a/src/cmd/go/internal/modload/buildlist.go +++ b/src/cmd/go/internal/modload/buildlist.go @@ -932,7 +932,7 @@ func tidyPrunedRoots(ctx context.Context, mainModule module.Version, old *Requir q.Add(func() { skipModFile := true _, _, _, _, err := importFromModules(ctx, pkg.path, tidy, nil, skipModFile) - if aie := (*AmbiguousImportError)(nil); errors.As(err, &aie) { + if _, ok := errors.AsType[*AmbiguousImportError](err); ok { disambiguateRoot.Store(pkg.mod, true) } }) diff --git a/src/cmd/go/internal/modload/edit.go b/src/cmd/go/internal/modload/edit.go index b406193dc5a673..d127194d3bb793 100644 --- a/src/cmd/go/internal/modload/edit.go +++ b/src/cmd/go/internal/modload/edit.go @@ -226,8 +226,10 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel // conflict we discover from one or more of the original roots. mg, upgradedRoots, err := extendGraph(ctx, rootPruning, roots, selectedRoot) if err != nil { - var tooNew *gover.TooNewError - if mg == nil || errors.As(err, &tooNew) { + if mg == nil { + return orig, false, err + } + if _, ok := errors.AsType[*gover.TooNewError](err); ok { return orig, false, err } // We're about to walk the entire extended module graph, so we will find diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go index 171d9d692fbb82..3d4cfca271292b 100644 --- a/src/cmd/go/internal/modload/import.go +++ b/src/cmd/go/internal/modload/import.go @@ -410,7 +410,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M root, isLocal, err := fetch(ctx, m) if err != nil { - if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) { + if _, ok := errors.AsType[*sumMissingError](err); ok { // We are missing a sum needed to fetch a module in the build list. // We can't verify that the package is unique, and we may not find // the package at all. Keep checking other modules to decide which @@ -549,7 +549,7 @@ func queryImport(ctx context.Context, path string, rs *Requirements) (module.Ver for _, m := range mods { root, isLocal, err := fetch(ctx, m) if err != nil { - if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) { + if _, ok := errors.AsType[*sumMissingError](err); ok { return module.Version{}, &ImportMissingSumError{importPath: path} } return module.Version{}, err diff --git a/src/cmd/go/internal/modload/list.go b/src/cmd/go/internal/modload/list.go index 53cb6c2ffe1406..555804de8a37ad 100644 --- a/src/cmd/go/internal/modload/list.go +++ b/src/cmd/go/internal/modload/list.go @@ -305,13 +305,11 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List // modinfoError wraps an error to create an error message in // modinfo.ModuleError with minimal redundancy. func modinfoError(path, vers string, err error) *modinfo.ModuleError { - var nerr *NoMatchingVersionError - var merr *module.ModuleError - if errors.As(err, &nerr) { + if _, ok := errors.AsType[*NoMatchingVersionError](err); ok { // NoMatchingVersionError contains the query, so we don't mention the // query again in ModuleError. err = &module.ModuleError{Path: path, Err: err} - } else if !errors.As(err, &merr) { + } else if _, ok := errors.AsType[*module.ModuleError](err); !ok { // If the error does not contain path and version, wrap it in a // module.ModuleError. err = &module.ModuleError{Path: path, Version: vers, Err: err} diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 8b2be3b300e9e1..6380e1cd9f3b49 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -1304,7 +1304,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader { } // Add importer information to checksum errors. - if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) { + if sumErr, ok := errors.AsType[*ImportMissingSumError](pkg.err); ok { if importer := pkg.stack; importer != nil { sumErr.importer = importer.path sumErr.importerVersion = importer.mod.Version @@ -1312,7 +1312,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader { } } - if stdErr := (*ImportMissingError)(nil); errors.As(pkg.err, &stdErr) && stdErr.isStd { + if stdErr, ok := errors.AsType[*ImportMissingError](pkg.err); ok && stdErr.isStd { // Add importer go version information to import errors of standard // library packages arising from newer releases. if importer := pkg.stack; importer != nil { @@ -1384,7 +1384,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err var maxTooNew *gover.TooNewError for _, pkg := range ld.pkgs { if pkg.err != nil { - if tooNew := (*gover.TooNewError)(nil); errors.As(pkg.err, &tooNew) { + if tooNew, ok := errors.AsType[*gover.TooNewError](pkg.err); ok { if maxTooNew == nil || gover.Compare(tooNew.GoVersion, maxTooNew.GoVersion) > 0 { maxTooNew = tooNew } @@ -1573,7 +1573,7 @@ func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[mod // we should only add the missing import once. continue } - if !errors.As(pkg.err, new(*ImportMissingError)) { + if _, ok := errors.AsType[*ImportMissingError](pkg.err); !ok { // Leave other errors for Import or load.Packages to report. continue } @@ -1584,8 +1584,7 @@ func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[mod var err error mod, err = queryImport(ctx, pkg.path, ld.requirements) if err != nil { - var ime *ImportMissingError - if errors.As(err, &ime) { + if ime, ok := errors.AsType[*ImportMissingError](err); ok { for curstack := pkg.stack; curstack != nil; curstack = curstack.stack { if MainModules.Contains(curstack.mod.Path) { ime.ImportingMainModule = curstack.mod @@ -1625,7 +1624,7 @@ func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[mod maxTooNewPkg *loadPkg ) for _, pm := range pkgMods { - if tooNew := (*gover.TooNewError)(nil); errors.As(pm.pkg.err, &tooNew) { + if tooNew, ok := errors.AsType[*gover.TooNewError](pm.pkg.err); ok { if maxTooNew == nil || gover.Compare(tooNew.GoVersion, maxTooNew.GoVersion) > 0 { maxTooNew = tooNew maxTooNewPkg = pm.pkg @@ -1771,8 +1770,7 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch // full module graph. m, _, _, _, err := importFromModules(ctx, path, ld.requirements, nil, ld.skipImportModFiles) if err != nil { - var missing *ImportMissingError - if errors.As(err, &missing) && ld.ResolveMissingImports { + if _, ok := errors.AsType[*ImportMissingError](err); ok && ld.ResolveMissingImports { // This package isn't provided by any selected module. // If we can find it, it will be a new root dependency. m, err = queryImport(ctx, path, ld.requirements) @@ -2196,14 +2194,14 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements, // module that previously provided the package to a version that no // longer does, or to a version for which the module source code (but // not the go.mod file in isolation) has a checksum error. - if missing := (*ImportMissingError)(nil); errors.As(mismatch.err, &missing) { + if _, ok := errors.AsType[*ImportMissingError](mismatch.err); ok { selected := module.Version{ Path: pkg.mod.Path, Version: mg.Selected(pkg.mod.Path), } ld.error(fmt.Errorf("%s loaded from %v,\n\tbut go %s would fail to locate it in %s", pkg.stackText(), pkg.mod, compatVersion, selected)) } else { - if ambiguous := (*AmbiguousImportError)(nil); errors.As(mismatch.err, &ambiguous) { + if _, ok := errors.AsType[*AmbiguousImportError](mismatch.err); ok { // TODO: Is this check needed? } ld.error(fmt.Errorf("%s loaded from %v,\n\tbut go %s would fail to locate it:\n\t%v", pkg.stackText(), pkg.mod, compatVersion, mismatch.err)) diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index 04e204cc984c59..42a38aa897d3f6 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -76,8 +76,7 @@ func ReadModFile(gomod string, fix modfile.VersionFixer) (data []byte, f *modfil } func shortPathErrorList(err error) error { - var el modfile.ErrorList - if errors.As(err, &el) { + if el, ok := errors.AsType[modfile.ErrorList](err); ok { for i := range el { el[i].Filename = base.ShortPath(el[i].Filename) } @@ -175,12 +174,15 @@ func (e *excludedError) Is(err error) bool { return err == ErrDisallowed } // its author. func CheckRetractions(ctx context.Context, m module.Version) (err error) { defer func() { - if retractErr := (*ModuleRetractedError)(nil); err == nil || errors.As(err, &retractErr) { + if err == nil { + return + } + if _, ok := errors.AsType[*ModuleRetractedError](err); ok { return } // Attribute the error to the version being checked, not the version from // which the retractions were to be loaded. - if mErr := (*module.ModuleError)(nil); errors.As(err, &mErr) { + if mErr, ok := errors.AsType[*module.ModuleError](err); ok { err = mErr.Err } err = &retractionLoadingError{m: m, err: err} diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index c4cf55442ba69b..145a8de0aeedd2 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -932,7 +932,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod if notExistErr == nil { notExistErr = rErr } - } else if iv := (*module.InvalidVersionError)(nil); errors.As(rErr, &iv) { + } else if _, ok := errors.AsType[*module.InvalidVersionError](rErr); ok { if invalidVersion == nil { invalidVersion = rErr } diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 8bfb3c149b6c69..611cf7e1308e3b 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -1735,8 +1735,7 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action) } else if errors.Is(err, exec.ErrWaitDelay) { fmt.Fprintf(cmd.Stdout, "*** Test I/O incomplete %v after exiting.\n", cmd.WaitDelay) } - var ee *exec.ExitError - if len(out) == 0 || !errors.As(err, &ee) || !ee.Exited() { + if ee, ok := errors.AsType[*exec.ExitError](err); !ok || !ee.Exited() || len(out) == 0 { // If there was no test output, print the exit status so that the reason // for failure is clear. fmt.Fprintf(cmd.Stdout, "%s\n", err) diff --git a/src/cmd/go/internal/test/testflag.go b/src/cmd/go/internal/test/testflag.go index 983e8f56e9af09..ba647209e9d4d3 100644 --- a/src/cmd/go/internal/test/testflag.go +++ b/src/cmd/go/internal/test/testflag.go @@ -260,7 +260,7 @@ func testFlags(args []string) (packageNames, passToTest []string) { break } - if nf := (cmdflag.NonFlagError{}); errors.As(err, &nf) { + if nf, ok := errors.AsType[cmdflag.NonFlagError](err); ok { if !inPkgList && packageNames != nil { // We already saw the package list previously, and this argument is not // a flag, so it — and everything after it — must be either a value for @@ -295,7 +295,7 @@ func testFlags(args []string) (packageNames, passToTest []string) { inPkgList = false } - if nd := (cmdflag.FlagNotDefinedError{}); errors.As(err, &nd) { + if nd, ok := errors.AsType[cmdflag.FlagNotDefinedError](err); ok { // This is a flag we do not know. We must assume that any args we see // after this might be flag arguments, not package names, so make // packageNames non-nil to indicate that the package list is complete. diff --git a/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go b/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go index 67234ac20d4628..6a6a0eee57ce85 100644 --- a/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go +++ b/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go @@ -155,10 +155,10 @@ func TestScripts(t *testing.T) { t.Log(buf) } if err != nil { - if notInstalled := (vcweb.ServerNotInstalledError{}); errors.As(err, ¬Installed) || errors.Is(err, exec.ErrNotFound) { + if _, ok := errors.AsType[vcweb.ServerNotInstalledError](err); ok || errors.Is(err, exec.ErrNotFound) { t.Skip(err) } - if skip := (vcweb.SkipError{}); errors.As(err, &skip) { + if skip, ok := errors.AsType[vcweb.SkipError](err); ok { if skip.Msg == "" { t.Skip("SKIP") } else { diff --git a/src/cmd/go/internal/vcweb/vcweb.go b/src/cmd/go/internal/vcweb/vcweb.go index b81ff5e63de72a..4b4e127bb042e0 100644 --- a/src/cmd/go/internal/vcweb/vcweb.go +++ b/src/cmd/go/internal/vcweb/vcweb.go @@ -244,9 +244,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { }) if err != nil { s.logger.Print(err) - if notFound := (ScriptNotFoundError{}); errors.As(err, ¬Found) { + if _, ok := errors.AsType[ScriptNotFoundError](err); ok { http.NotFound(w, req) - } else if notInstalled := (ServerNotInstalledError{}); errors.As(err, ¬Installed) || errors.Is(err, exec.ErrNotFound) { + } else if _, ok := errors.AsType[ServerNotInstalledError](err); ok || errors.Is(err, exec.ErrNotFound) { http.Error(w, err.Error(), http.StatusNotImplemented) } else { http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/src/cmd/go/internal/version/version.go b/src/cmd/go/internal/version/version.go index c26dd42b4e1a08..781bc080e89fe4 100644 --- a/src/cmd/go/internal/version/version.go +++ b/src/cmd/go/internal/version/version.go @@ -168,7 +168,7 @@ func scanFile(file string, info fs.FileInfo, mustPrint bool) bool { bi, err := buildinfo.ReadFile(file) if err != nil { if mustPrint { - if pathErr := (*os.PathError)(nil); errors.As(err, &pathErr) && filepath.Clean(pathErr.Path) == filepath.Clean(file) { + if pathErr, ok := errors.AsType[*os.PathError](err); ok && filepath.Clean(pathErr.Path) == filepath.Clean(file) { fmt.Fprintf(os.Stderr, "%v\n", file) } else { // Skip errors for non-Go binaries. diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go index d0bdb58a504ae7..f5454e2774d835 100644 --- a/src/cmd/go/internal/vet/vetflag.go +++ b/src/cmd/go/internal/vet/vetflag.go @@ -142,7 +142,7 @@ func vetFlags(args []string) (passToVet, packageNames []string) { break } - if nf := (cmdflag.NonFlagError{}); errors.As(err, &nf) { + if _, ok := errors.AsType[cmdflag.NonFlagError](err); ok { // Everything from here on out — including the argument we just consumed — // must be a package name. packageNames = args diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 6741b39f051cd6..a7d9f3aba4cd46 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -705,7 +705,7 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) { continue } haveErrors = true - if missingErr := (*modload.ImportMissingError)(nil); !errors.As(pkg.Error, &missingErr) { + if _, ok := errors.AsType[*modload.ImportMissingError](pkg.Error); !ok { allMissingErrors = false break } diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 72b9177c9dbbeb..f12aed72422240 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -169,9 +169,10 @@ func (b *Builder) Do(ctx context.Context, root *Action) { a.Package.Incomplete = true } } else { - var ipe load.ImportPathError - if a.Package != nil && (!errors.As(err, &ipe) || ipe.ImportPath() != a.Package.ImportPath) { - err = fmt.Errorf("%s: %v", a.Package.ImportPath, err) + if a.Package != nil { + if ipe, ok := errors.AsType[load.ImportPathError](err); !ok || ipe.ImportPath() != a.Package.ImportPath { + err = fmt.Errorf("%s: %v", a.Package.ImportPath, err) + } } sh := b.Shell(a) sh.Errorf("%s", err) diff --git a/src/cmd/internal/bootstrap_test/experiment_toolid_test.go b/src/cmd/internal/bootstrap_test/experiment_toolid_test.go index ff2379c8998c76..ca292b700861a9 100644 --- a/src/cmd/internal/bootstrap_test/experiment_toolid_test.go +++ b/src/cmd/internal/bootstrap_test/experiment_toolid_test.go @@ -97,7 +97,7 @@ func runCmd(t *testing.T, dir string, env []string, path string, args ...string) cmd.Env = env out, err := cmd.Output() if err != nil { - if ee := (*exec.ExitError)(nil); errors.As(err, &ee) { + if ee, ok := errors.AsType[*exec.ExitError](err); ok { out = append(out, ee.Stderr...) } t.Fatalf("%s failed:\n%s\n%s", cmd, out, err) diff --git a/src/cmd/internal/robustio/robustio_darwin.go b/src/cmd/internal/robustio/robustio_darwin.go index 99fd8ebc2fff18..69ea2479308dea 100644 --- a/src/cmd/internal/robustio/robustio_darwin.go +++ b/src/cmd/internal/robustio/robustio_darwin.go @@ -13,9 +13,6 @@ const errFileNotFound = syscall.ENOENT // isEphemeralError returns true if err may be resolved by waiting. func isEphemeralError(err error) bool { - var errno syscall.Errno - if errors.As(err, &errno) { - return errno == errFileNotFound - } - return false + errno, ok := errors.AsType[syscall.Errno](err) + return ok && errno == errFileNotFound } diff --git a/src/cmd/internal/robustio/robustio_flaky.go b/src/cmd/internal/robustio/robustio_flaky.go index c56e36ca62412a..ec1a2daea65852 100644 --- a/src/cmd/internal/robustio/robustio_flaky.go +++ b/src/cmd/internal/robustio/robustio_flaky.go @@ -31,8 +31,7 @@ func retry(f func() (err error, mayRetry bool)) error { return err } - var errno syscall.Errno - if errors.As(err, &errno) && (lowestErrno == 0 || errno < lowestErrno) { + if errno, ok := errors.AsType[syscall.Errno](err); ok && (lowestErrno == 0 || errno < lowestErrno) { bestErr = err lowestErrno = errno } else if bestErr == nil { diff --git a/src/cmd/internal/robustio/robustio_windows.go b/src/cmd/internal/robustio/robustio_windows.go index 687dcb66f83d15..ad46ec5cfeb601 100644 --- a/src/cmd/internal/robustio/robustio_windows.go +++ b/src/cmd/internal/robustio/robustio_windows.go @@ -14,8 +14,7 @@ const errFileNotFound = syscall.ERROR_FILE_NOT_FOUND // isEphemeralError returns true if err may be resolved by waiting. func isEphemeralError(err error) bool { - var errno syscall.Errno - if errors.As(err, &errno) { + if errno, ok := errors.AsType[syscall.Errno](err); ok { switch errno { case syscall.ERROR_ACCESS_DENIED, syscall.ERROR_FILE_NOT_FOUND, diff --git a/src/cmd/internal/script/engine.go b/src/cmd/internal/script/engine.go index eb9344f6e2a1eb..4607868379488a 100644 --- a/src/cmd/internal/script/engine.go +++ b/src/cmd/internal/script/engine.go @@ -185,7 +185,7 @@ func (e *Engine) Execute(s *State, file string, script *bufio.Reader, log io.Wri var lineno int lineErr := func(err error) error { - if errors.As(err, new(*CommandError)) { + if _, ok := errors.AsType[*CommandError](err); ok { return err } return fmt.Errorf("%s:%d: %w", file, lineno, err) @@ -283,7 +283,7 @@ func (e *Engine) Execute(s *State, file string, script *bufio.Reader, log io.Wri // Run the command. err = e.runCommand(s, cmd, impl) if err != nil { - if stop := (stopError{}); errors.As(err, &stop) { + if stop, ok := errors.AsType[stopError](err); ok { // Since the 'stop' command halts execution of the entire script, // log its message separately from the section in which it appears. err = endSection(true) @@ -607,13 +607,13 @@ func checkStatus(cmd *command, err error) error { return nil } - if s := (stopError{}); errors.As(err, &s) { + if _, ok := errors.AsType[stopError](err); ok { // This error originated in the Stop command. // Propagate it as-is. return cmdError(cmd, err) } - if w := (waitError{}); errors.As(err, &w) { + if _, ok := errors.AsType[waitError](err); ok { // This error was surfaced from a background process by a call to Wait. // Add a call frame for Wait itself, but ignore its "want" field. // (Wait itself cannot fail to wait on commands or else it would leak diff --git a/src/cmd/internal/script/scripttest/scripttest.go b/src/cmd/internal/script/scripttest/scripttest.go index bace662a6722fd..349201fd188c1b 100644 --- a/src/cmd/internal/script/scripttest/scripttest.go +++ b/src/cmd/internal/script/scripttest/scripttest.go @@ -89,7 +89,7 @@ func Run(t testing.TB, e *script.Engine, s *script.State, filename string, testS return e.Execute(s, filename, bufio.NewReader(testScript), log) }() - if skip := (skipError{}); errors.As(err, &skip) { + if skip, ok := errors.AsType[skipError](err); ok { if skip.msg == "" { t.Skip("SKIP") } else { diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 0125ba8e0f56be..31822d21f39d31 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -1532,11 +1532,13 @@ func TestFlagS(t *testing.T) { } cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "nm", exe) out, err = cmd.CombinedOutput() - if err != nil && !errors.As(err, new(*exec.ExitError)) { - // Error exit is fine as it may have no symbols. - // On darwin we need to emit dynamic symbol references so it - // actually has some symbols, and nm succeeds. - t.Errorf("(mode=%s) go tool nm failed: %v\n%s", mode, err, out) + if err != nil { + if _, ok := errors.AsType[*exec.ExitError](err); !ok { + // Error exit is fine as it may have no symbols. + // On darwin we need to emit dynamic symbol references so it + // actually has some symbols, and nm succeeds. + t.Errorf("(mode=%s) go tool nm failed: %v\n%s", mode, err, out) + } } for _, s := range syms { if bytes.Contains(out, []byte(s)) { diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go index 09dc9ea94c939f..2de120a1329f87 100644 --- a/src/crypto/tls/conn.go +++ b/src/crypto/tls/conn.go @@ -1578,9 +1578,9 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) { // the handshake (RFC 9001, Section 5.7). c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret) } else { - var a alert c.out.Lock() - if !errors.As(c.out.err, &a) { + a, ok := errors.AsType[alert](c.out.err) + if !ok { a = alertInternalError } c.out.Unlock() diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index 088c66fadb2a44..a2cf176a86c0d8 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -965,10 +965,9 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error { chains, err := certs[0].Verify(opts) if err != nil { - var errCertificateInvalid x509.CertificateInvalidError - if errors.As(err, &x509.UnknownAuthorityError{}) { + if _, ok := errors.AsType[x509.UnknownAuthorityError](err); ok { c.sendAlert(alertUnknownCA) - } else if errors.As(err, &errCertificateInvalid) && errCertificateInvalid.Reason == x509.Expired { + } else if errCertificateInvalid, ok := errors.AsType[x509.CertificateInvalidError](err); ok && errCertificateInvalid.Reason == x509.Expired { c.sendAlert(alertCertificateExpired) } else { c.sendAlert(alertBadCertificate) diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go index 941f2a3373feb9..43183db2a19770 100644 --- a/src/crypto/tls/handshake_server_test.go +++ b/src/crypto/tls/handshake_server_test.go @@ -403,8 +403,7 @@ func TestAlertForwarding(t *testing.T) { err := Server(s, testConfig).Handshake() s.Close() - var opErr *net.OpError - if !errors.As(err, &opErr) || opErr.Err != error(alertUnknownCA) { + if opErr, ok := errors.AsType[*net.OpError](err); !ok || opErr.Err != error(alertUnknownCA) { t.Errorf("Got error: %s; expected: %s", err, error(alertUnknownCA)) } } diff --git a/src/crypto/tls/quic.go b/src/crypto/tls/quic.go index 3be479eb12f085..2ba2242b2d93d2 100644 --- a/src/crypto/tls/quic.go +++ b/src/crypto/tls/quic.go @@ -362,12 +362,11 @@ func quicError(err error) error { if err == nil { return nil } - var ae AlertError - if errors.As(err, &ae) { + if _, ok := errors.AsType[AlertError](err); ok { return err } - var a alert - if !errors.As(err, &a) { + a, ok := errors.AsType[alert](err) + if !ok { a = alertInternalError } // Return an error wrapping the original error and an AlertError. diff --git a/src/crypto/tls/quic_test.go b/src/crypto/tls/quic_test.go index f6e8c55d9d63e4..5f4b2b7707d01e 100644 --- a/src/crypto/tls/quic_test.go +++ b/src/crypto/tls/quic_test.go @@ -368,8 +368,7 @@ func TestQUICHandshakeError(t *testing.T) { if !errors.Is(err, AlertError(alertBadCertificate)) { t.Errorf("connection handshake terminated with error %q, want alertBadCertificate", err) } - var e *CertificateVerificationError - if !errors.As(err, &e) { + if _, ok := errors.AsType[*CertificateVerificationError](err); !ok { t.Errorf("connection handshake terminated with error %q, want CertificateVerificationError", err) } } diff --git a/src/debug/buildinfo/buildinfo.go b/src/debug/buildinfo/buildinfo.go index 12e3b750d233a7..d202d5050a2786 100644 --- a/src/debug/buildinfo/buildinfo.go +++ b/src/debug/buildinfo/buildinfo.go @@ -67,7 +67,7 @@ const ( // with module support. func ReadFile(name string) (info *BuildInfo, err error) { defer func() { - if pathErr := (*fs.PathError)(nil); errors.As(err, &pathErr) { + if _, ok := errors.AsType[*fs.PathError](err); ok { err = fmt.Errorf("could not read Go build info: %w", err) } else if err != nil { err = fmt.Errorf("could not read Go build info from %s: %w", name, err) diff --git a/src/encoding/json/jsontext/coder_test.go b/src/encoding/json/jsontext/coder_test.go index 4a9efb3b8f97a5..8602e3e7fff286 100644 --- a/src/encoding/json/jsontext/coder_test.go +++ b/src/encoding/json/jsontext/coder_test.go @@ -486,7 +486,7 @@ func testCoderInterleaved(t *testing.T, where jsontest.CasePos, modeName string, // Retry as a ReadToken call. expectError := dec.PeekKind() == '}' || dec.PeekKind() == ']' if expectError { - if !errors.As(err, new(*SyntacticError)) { + if _, ok := errors.AsType[*SyntacticError](err); !ok { t.Fatalf("%s: Decoder.ReadToken error is %T, want %T", where, err, new(SyntacticError)) } tickTock = !tickTock diff --git a/src/encoding/json/jsontext/fuzz_test.go b/src/encoding/json/jsontext/fuzz_test.go index 60d16b9e27805c..3ad181d43416b8 100644 --- a/src/encoding/json/jsontext/fuzz_test.go +++ b/src/encoding/json/jsontext/fuzz_test.go @@ -53,9 +53,10 @@ func FuzzCoder(f *testing.F) { } else { val, err := dec.ReadValue() if err != nil { - expectError := dec.PeekKind() == '}' || dec.PeekKind() == ']' - if expectError && errors.As(err, new(*SyntacticError)) { - continue + if expectError := dec.PeekKind() == '}' || dec.PeekKind() == ']'; expectError { + if _, ok := errors.AsType[*SyntacticError](err); ok { + continue + } } if err == io.EOF { break diff --git a/src/encoding/json/jsontext/state.go b/src/encoding/json/jsontext/state.go index d214fd5190325e..538dfe32bfa9d2 100644 --- a/src/encoding/json/jsontext/state.go +++ b/src/encoding/json/jsontext/state.go @@ -24,8 +24,7 @@ import ( // The name of a duplicate JSON object member can be extracted as: // // err := ... -// var serr jsontext.SyntacticError -// if errors.As(err, &serr) && serr.Err == jsontext.ErrDuplicateName { +// if serr, ok := errors.AsType[jsontext.SyntacticError](err); ok && serr.Err == jsontext.ErrDuplicateName { // ptr := serr.JSONPointer // JSON pointer to duplicate name // name := ptr.LastToken() // duplicate name itself // ... diff --git a/src/encoding/json/v2/errors.go b/src/encoding/json/v2/errors.go index 9485d7b527793c..0f50d608c9ed27 100644 --- a/src/encoding/json/v2/errors.go +++ b/src/encoding/json/v2/errors.go @@ -28,8 +28,7 @@ import ( // The name of an unknown JSON object member can be extracted as: // // err := ... -// var serr json.SemanticError -// if errors.As(err, &serr) && serr.Err == json.ErrUnknownName { +// if serr, ok := errors.AsType[json.SemanticError](err); ok && serr.Err == json.ErrUnknownName { // ptr := serr.JSONPointer // JSON pointer to unknown name // name := ptr.LastToken() // unknown name itself // ... diff --git a/src/encoding/json/v2/example_test.go b/src/encoding/json/v2/example_test.go index c6bf0a864d8385..6d539bbd36b529 100644 --- a/src/encoding/json/v2/example_test.go +++ b/src/encoding/json/v2/example_test.go @@ -371,8 +371,7 @@ func Example_unknownMembers() { // Specifying RejectUnknownMembers causes Unmarshal // to reject the presence of any unknown members. err = json.Unmarshal([]byte(input), new(Color), json.RejectUnknownMembers(true)) - var serr *json.SemanticError - if errors.As(err, &serr) && serr.Err == json.ErrUnknownName { + if serr, ok := errors.AsType[*json.SemanticError](err); ok && serr.Err == json.ErrUnknownName { fmt.Println("Unmarshal error:", serr.Err, strconv.Quote(serr.JSONPointer.LastToken())) } diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index f7a98ae28061bb..2798b9e0c4eb47 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -2480,8 +2480,8 @@ func TestInstantiateErrors(t *testing.T) { t.Fatalf("Instantiate(%v, %v) returned nil error, want non-nil", T, test.targs) } - var argErr *ArgumentError - if !errors.As(err, &argErr) { + argErr, ok := errors.AsType[*ArgumentError](err) + if !ok { t.Fatalf("Instantiate(%v, %v): error is not an *ArgumentError", T, test.targs) } @@ -2496,8 +2496,8 @@ func TestArgumentErrorUnwrapping(t *testing.T) { Index: 1, Err: Error{Msg: "test"}, } - var e Error - if !errors.As(err, &e) { + e, ok := errors.AsType[Error](err) + if !ok { t.Fatalf("error %v does not wrap types.Error", err) } if e.Msg != "test" { diff --git a/src/internal/runtime/wasitest/testdata/tcpecho.go b/src/internal/runtime/wasitest/testdata/tcpecho.go index 819e3526885642..6da56acba10a1c 100644 --- a/src/internal/runtime/wasitest/testdata/tcpecho.go +++ b/src/internal/runtime/wasitest/testdata/tcpecho.go @@ -62,8 +62,7 @@ func findListener() (net.Listener, error) { l, err := net.FileListener(f) f.Close() - var se syscall.Errno - switch errors.As(err, &se); se { + switch se, _ := errors.AsType[syscall.Errno](err); se { case syscall.ENOTSOCK: continue case syscall.EBADF: diff --git a/src/internal/testenv/testenv_unix.go b/src/internal/testenv/testenv_unix.go index a629078842eadc..22eeca220da017 100644 --- a/src/internal/testenv/testenv_unix.go +++ b/src/internal/testenv/testenv_unix.go @@ -21,8 +21,7 @@ func syscallIsNotSupported(err error) bool { return false } - var errno syscall.Errno - if errors.As(err, &errno) { + if errno, ok := errors.AsType[syscall.Errno](err); ok { switch errno { case syscall.EPERM, syscall.EROFS: // User lacks permission: either the call requires root permission and the diff --git a/src/io/fs/readdir_test.go b/src/io/fs/readdir_test.go index 4c409ae7a010e2..30f5ad051004b5 100644 --- a/src/io/fs/readdir_test.go +++ b/src/io/fs/readdir_test.go @@ -94,8 +94,8 @@ func TestFileInfoToDirEntry(t *testing.T) { } func errorPath(err error) string { - var perr *PathError - if !errors.As(err, &perr) { + perr, ok := errors.AsType[*PathError](err) + if !ok { return "" } return perr.Path diff --git a/src/log/log_test.go b/src/log/log_test.go index 8cc05c5e647f95..5d5d38cc10dbae 100644 --- a/src/log/log_test.go +++ b/src/log/log_test.go @@ -272,8 +272,7 @@ func TestCallDepth(t *testing.T) { cmd.Env = append(cmd.Environ(), envVar+"=1") out, err := cmd.CombinedOutput() - var exitErr *exec.ExitError - if !errors.As(err, &exitErr) { + if _, ok := errors.AsType[*exec.ExitError](err); !ok { t.Fatalf("expected exec.ExitError: %v", err) } diff --git a/src/log/slog/logger_test.go b/src/log/slog/logger_test.go index bf645d9c4c6310..edacef13a4d518 100644 --- a/src/log/slog/logger_test.go +++ b/src/log/slog/logger_test.go @@ -303,8 +303,7 @@ func TestCallDepthConnection(t *testing.T) { cmd.Env = append(cmd.Environ(), envVar+"=1") out, err := cmd.CombinedOutput() - var exitErr *exec.ExitError - if !errors.As(err, &exitErr) { + if _, ok := errors.AsType[*exec.ExitError](err); !ok { t.Fatalf("expected exec.ExitError: %v", err) } diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index 5e060a6b489bf9..940fcccf7f2139 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -842,8 +842,7 @@ func (r *Resolver) goLookupPTR(ctx context.Context, addr string, order hostLooku } p, server, err := r.lookup(ctx, arpa, dnsmessage.TypePTR, conf) if err != nil { - var dnsErr *DNSError - if errors.As(err, &dnsErr) && dnsErr.IsNotFound { + if dnsErr, ok := errors.AsType[*DNSError](err); ok && dnsErr.IsNotFound { if order == hostLookupDNSFiles { names := lookupStaticAddr(addr) if len(names) > 0 { diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 826b4daba1e7fd..fc1d40f18b6f9a 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -2627,8 +2627,7 @@ func TestLongDNSNames(t *testing.T) { } expectedErr := DNSError{Err: errNoSuchHost.Error(), Name: v.req, IsNotFound: true} - var dnsErr *DNSError - errors.As(err, &dnsErr) + dnsErr, _ := errors.AsType[*DNSError](err) if dnsErr == nil || *dnsErr != expectedErr { t.Errorf("%v: Lookup%v: unexpected error: %v", i, testName, err) } @@ -2820,8 +2819,7 @@ func TestLookupOrderFilesNoSuchHost(t *testing.T) { } expectedErr := DNSError{Err: errNoSuchHost.Error(), Name: testName, IsNotFound: true} - var dnsErr *DNSError - errors.As(err, &dnsErr) + dnsErr, _ := errors.AsType[*DNSError](err) if dnsErr == nil || *dnsErr != expectedErr { t.Errorf("Lookup%v: unexpected error: %v", v.name, err) } @@ -2853,8 +2851,7 @@ func TestExtendedRCode(t *testing.T) { r := &Resolver{PreferGo: true, Dial: fake.DialContext} _, _, err := r.tryOneName(context.Background(), getSystemDNSConfig(), "go.dev.", dnsmessage.TypeA) - var dnsErr *DNSError - if !(errors.As(err, &dnsErr) && dnsErr.Err == errServerMisbehaving.Error()) { + if dnsErr, ok := errors.AsType[*DNSError](err); !ok || dnsErr.Err != errServerMisbehaving.Error() { t.Fatalf("r.tryOneName(): unexpected error: %v", err) } } diff --git a/src/net/http/h2_error_test.go b/src/net/http/h2_error_test.go index 5e400683b415e7..e71825451a8e32 100644 --- a/src/net/http/h2_error_test.go +++ b/src/net/http/h2_error_test.go @@ -25,19 +25,18 @@ func (e externalStreamError) Error() string { } func TestStreamError(t *testing.T) { - var target externalStreamError streamErr := http2streamError(42, http2ErrCodeProtocol) - ok := errors.As(streamErr, &target) + extStreamErr, ok := errors.AsType[externalStreamError](streamErr) if !ok { - t.Fatalf("errors.As failed") + t.Fatalf("errors.AsType failed") } - if target.StreamID != streamErr.StreamID { - t.Errorf("got StreamID %v, expected %v", target.StreamID, streamErr.StreamID) + if extStreamErr.StreamID != streamErr.StreamID { + t.Errorf("got StreamID %v, expected %v", extStreamErr.StreamID, streamErr.StreamID) } - if target.Cause != streamErr.Cause { - t.Errorf("got Cause %v, expected %v", target.Cause, streamErr.Cause) + if extStreamErr.Cause != streamErr.Cause { + t.Errorf("got Cause %v, expected %v", extStreamErr.Cause, streamErr.Cause) } - if uint32(target.Code) != uint32(streamErr.Code) { - t.Errorf("got Code %v, expected %v", target.Code, streamErr.Code) + if uint32(extStreamErr.Code) != uint32(streamErr.Code) { + t.Errorf("got Code %v, expected %v", extStreamErr.Code, streamErr.Code) } } diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index 514cbd098ae772..2a774100a8ec67 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -1420,8 +1420,8 @@ func testLookupNoData(t *testing.T, prefix string) { return } - var dnsErr *DNSError - if errors.As(err, &dnsErr) { + dnsErr, ok := errors.AsType[*DNSError](err) + if ok { succeeded := true if !dnsErr.IsNotFound { succeeded = false @@ -1455,8 +1455,7 @@ func testLookupNoData(t *testing.T, prefix string) { func TestLookupPortNotFound(t *testing.T) { allResolvers(t, func(t *testing.T) { _, err := LookupPort("udp", "_-unknown-service-") - var dnsErr *DNSError - if !errors.As(err, &dnsErr) || !dnsErr.IsNotFound { + if dnsErr, ok := errors.AsType[*DNSError](err); !ok || !dnsErr.IsNotFound { t.Fatalf("unexpected error: %v", err) } }) @@ -1475,8 +1474,7 @@ var tcpOnlyService = func() string { func TestLookupPortDifferentNetwork(t *testing.T) { allResolvers(t, func(t *testing.T) { _, err := LookupPort("udp", tcpOnlyService) - var dnsErr *DNSError - if !errors.As(err, &dnsErr) || !dnsErr.IsNotFound { + if dnsErr, ok := errors.AsType[*DNSError](err); !ok || !dnsErr.IsNotFound { t.Fatalf("unexpected error: %v", err) } }) diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go index 3bded3dea604fb..1decebdc222d23 100644 --- a/src/os/exec/exec_test.go +++ b/src/os/exec/exec_test.go @@ -1378,8 +1378,8 @@ func TestWaitInterrupt(t *testing.T) { // The child process should be reported as failed, // and the grandchild will exit (or die by SIGPIPE) once the // stderr pipe is closed. - if ee := new(*exec.ExitError); !errors.As(err, ee) { - t.Errorf("Wait error = %v; want %T", err, *ee) + if ee, ok := errors.AsType[*exec.ExitError](err); !ok { + t.Errorf("Wait error = %v; want %T", err, ee) } }) @@ -1423,8 +1423,8 @@ func TestWaitInterrupt(t *testing.T) { // This command ignores SIGINT, sleeping until it is killed. // Wait should return the usual error for a killed process. - if ee := new(*exec.ExitError); !errors.As(err, ee) { - t.Errorf("Wait error = %v; want %T", err, *ee) + if ee, ok := errors.AsType[*exec.ExitError](err); !ok { + t.Errorf("Wait error = %v; want %T", err, ee) } }) @@ -1471,7 +1471,7 @@ func TestWaitInterrupt(t *testing.T) { t.Logf("stderr:\n%s", cmd.Stderr) t.Logf("[%d] %v", cmd.Process.Pid, err) - if ee := new(*exec.ExitError); !errors.As(err, ee) { + if _, ok := errors.AsType[*exec.ExitError](err); !ok { t.Errorf("Wait error = %v; want %v", err, ctx.Err()) } diff --git a/src/os/os_test.go b/src/os/os_test.go index 9f6eb13e1f96a9..536734901baff6 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -840,8 +840,7 @@ func TestReaddirOfFile(t *testing.T) { if err == nil { t.Error("Readdirnames succeeded; want non-nil error") } - var pe *PathError - if !errors.As(err, &pe) || pe.Path != f.Name() { + if pe, ok := errors.AsType[*PathError](err); !ok || pe.Path != f.Name() { t.Errorf("Readdirnames returned %q; want a PathError with path %q", err, f.Name()) } if len(names) > 0 { diff --git a/src/runtime/pprof/proto_windows.go b/src/runtime/pprof/proto_windows.go index f4dc44bd078eac..3118e8911e28ec 100644 --- a/src/runtime/pprof/proto_windows.go +++ b/src/runtime/pprof/proto_windows.go @@ -67,8 +67,7 @@ func readMainModuleMapping() (start, end uint64, exe, buildID string, err error) func createModuleSnapshot() (syscall.Handle, error) { for { snap, err := syscall.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE|windows.TH32CS_SNAPMODULE32, uint32(syscall.Getpid())) - var errno syscall.Errno - if err != nil && errors.As(err, &errno) && errno == windows.ERROR_BAD_LENGTH { + if errno, ok := errors.AsType[syscall.Errno](err); ok && errno == windows.ERROR_BAD_LENGTH { // When CreateToolhelp32Snapshot(SNAPMODULE|SNAPMODULE32, ...) fails // with ERROR_BAD_LENGTH then it should be retried until it succeeds. continue diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 1fb84b892842cb..72830a09a727bd 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -29,7 +29,7 @@ import ( // The contents of fsys must not change concurrently with TestFS. // // If TestFS finds any misbehaviors, it returns either the first error or a -// list of errors. Use [errors.Is] or [errors.As] to inspect. +// list of errors. Use [errors.Is] or [errors.AsType] to inspect. // // Typical usage inside a test is: // diff --git a/src/testing/fstest/testfs_test.go b/src/testing/fstest/testfs_test.go index d6d6d89b89fdaa..e3d7f1ab44d7b7 100644 --- a/src/testing/fstest/testfs_test.go +++ b/src/testing/fstest/testfs_test.go @@ -105,8 +105,12 @@ func TestTestFSWrappedErrors(t *testing.T) { // TestFS is expected to return a list of errors. // Enforce that the list can be extracted for browsing. - var errs interface{ Unwrap() []error } - if !errors.As(err, &errs) { + type wrapper interface{ + error + Unwrap() []error + } + errs, ok := errors.AsType[wrapper](err) + if !ok { t.Errorf("caller should be able to extract the errors as a list: %#v", err) } else { for _, err := range errs.Unwrap() { diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index 65440901a0b4ec..8665f3ad4987c2 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -1015,8 +1015,7 @@ func TestExecError_CustomError(t *testing.T) { var b bytes.Buffer err := tmpl.Execute(&b, nil) - var e *CustomError - if !errors.As(err, &e) { + if _, ok := errors.AsType[*CustomError](err); !ok { t.Fatalf("expected custom error; got %s", err) } } diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go index c28c3ea2002d21..30b3243a5a8416 100644 --- a/src/text/template/funcs.go +++ b/src/text/template/funcs.go @@ -22,7 +22,7 @@ import ( // return value evaluates to non-nil during execution, execution terminates and // Execute returns that error. // -// Errors returned by Execute wrap the underlying error; call [errors.As] to +// Errors returned by Execute wrap the underlying error; call [errors.AsType] to // unwrap them. // // When template execution invokes a function with an argument list, that list