codekingpro/portable-devtools
114k
1// Copyright 2018 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5package errors6 7import (8 "internal/reflectlite"9)10 11// Unwrap returns the result of calling the Unwrap method on err, if err's12// type contains an Unwrap method returning error.13// Otherwise, Unwrap returns nil.14//15// Unwrap only calls a method of the form "Unwrap() error".16// In particular Unwrap does not unwrap errors returned by [Join].17func Unwrap(err error) error {18 u, ok := err.(interface {19 Unwrap() error20 })21 if !ok {22 return nil23 }24 return u.Unwrap()25}26 27// Is reports whether any error in err's tree matches target.28// The target must be comparable.29//30// The tree consists of err itself, followed by the errors obtained by repeatedly31// calling its Unwrap() error or Unwrap() []error method. When err wraps multiple32// errors, Is examines err followed by a depth-first traversal of its children.33//34// An error is considered to match a target if it is equal to that target or if35// it implements a method Is(error) bool such that Is(target) returns true.36//37// An error type might provide an Is method so it can be treated as equivalent38// to an existing error. For example, if MyError defines39//40// func (m MyError) Is(target error) bool { return target == fs.ErrExist }41//42// then Is(MyError{}, fs.ErrExist) returns true. See [syscall.Errno.Is] for43// an example in the standard library. An Is method should only shallowly44// compare err and the target and not call [Unwrap] on either.45func Is(err, target error) bool {46 if err == nil || target == nil {47 return err == target48 }49 50 isComparable := reflectlite.TypeOf(target).Comparable()51 return is(err, target, isComparable)52}53 54func is(err, target error, targetComparable bool) bool {55 for {56 if targetComparable && err == target {57 return true58 }59 if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {60 return true61 }62 switch x := err.(type) {63 case interface{ Unwrap() error }:64 err = x.Unwrap()65 if err == nil {66 return false67 }68 case interface{ Unwrap() []error }:69 for _, err := range x.Unwrap() {70 if is(err, target, targetComparable) {71 return true72 }73 }74 return false75 default:76 return false77 }78 }79}80 81// As finds the first error in err's tree that matches target, and if one is found, sets82// target to that error value and returns true. Otherwise, it returns false.83//84// For most uses, prefer [AsType]. As is equivalent to [AsType] but sets its target85// argument rather than returning the matching error and doesn't require its target86// argument to implement error.87//88// The tree consists of err itself, followed by the errors obtained by repeatedly89// calling its Unwrap() error or Unwrap() []error method. When err wraps multiple90// errors, As examines err followed by a depth-first traversal of its children.91//92// An error matches target if the error's concrete value is assignable to the value93// pointed to by target, or if the error has a method As(any) bool such that94// As(target) returns true. In the latter case, the As method is responsible for95// setting target.96//97// An error type might provide an As method so it can be treated as if it were a98// different error type.99//100// As panics if target is not a non-nil pointer to either a type that implements101// error, or to any interface type.102func As(err error, target any) bool {103 if err == nil {104 return false105 }106 if target == nil {107 panic("errors: target cannot be nil")108 }109 val := reflectlite.ValueOf(target)110 typ := val.Type()111 if typ.Kind() != reflectlite.Ptr || val.IsNil() {112 panic("errors: target must be a non-nil pointer")113 }114 targetType := typ.Elem()115 if targetType.Kind() != reflectlite.Interface && !targetType.Implements(errorType) {116 panic("errors: *target must be interface or implement error")117 }118 return as(err, target, val, targetType)119}120 121func as(err error, target any, targetVal reflectlite.Value, targetType reflectlite.Type) bool {122 for {123 if reflectlite.TypeOf(err).AssignableTo(targetType) {124 targetVal.Elem().Set(reflectlite.ValueOf(err))125 return true126 }127 if x, ok := err.(interface{ As(any) bool }); ok && x.As(target) {128 return true129 }130 switch x := err.(type) {131 case interface{ Unwrap() error }:132 err = x.Unwrap()133 if err == nil {134 return false135 }136 case interface{ Unwrap() []error }:137 for _, err := range x.Unwrap() {138 if err == nil {139 continue140 }141 if as(err, target, targetVal, targetType) {142 return true143 }144 }145 return false146 default:147 return false148 }149 }150}151 152var errorType = reflectlite.TypeOf((*error)(nil)).Elem()153 154// AsType finds the first error in err's tree that matches the type E, and155// if one is found, returns that error value and true. Otherwise, it156// returns the zero value of E and false.157//158// The tree consists of err itself, followed by the errors obtained by159// repeatedly calling its Unwrap() error or Unwrap() []error method. When160// err wraps multiple errors, AsType examines err followed by a161// depth-first traversal of its children.162//163// An error err matches the type E if the type assertion err.(E) holds,164// or if the error has a method As(any) bool such that err.As(target)165// returns true when target is a non-nil *E. In the latter case, the As166// method is responsible for setting target.167func AsType[E error](err error) (E, bool) {168 if err == nil {169 var zero E170 return zero, false171 }172 var pe *E // lazily initialized173 return asType(err, &pe)174}175 176func asType[E error](err error, ppe **E) (_ E, _ bool) {177 for {178 if e, ok := err.(E); ok {179 return e, true180 }181 if x, ok := err.(interface{ As(any) bool }); ok {182 if *ppe == nil {183 *ppe = new(E)184 }185 if x.As(*ppe) {186 return **ppe, true187 }188 }189 switch x := err.(type) {190 case interface{ Unwrap() error }:191 err = x.Unwrap()192 if err == nil {193 return194 }195 case interface{ Unwrap() []error }:196 for _, err := range x.Unwrap() {197 if err == nil {198 continue199 }200 if x, ok := asType(err, ppe); ok {201 return x, true202 }203 }204 return205 default:206 return207 }208 }209}210 