1// Copyright 2018 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package errors 6 7import ( 8 "internal/reflectlite" 9) 10 11// Unwrap returns the result of calling the Unwrap method on err, if err's 12// 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() error 20 }) 21 if !ok { 22 return nil 23 } 24 return u.Unwrap() 25} 26 27// Is reports whether any error in err's tree matches target. 28// 29// The tree consists of err itself, followed by the errors obtained by repeatedly 30// calling its Unwrap() error or Unwrap() []error method. When err wraps multiple 31// errors, Is examines err followed by a depth-first traversal of its children. 32// 33// An error is considered to match a target if it is equal to that target or if 34// it implements a method Is(error) bool such that Is(target) returns true. 35// 36// An error type might provide an Is method so it can be treated as equivalent 37// to an existing error. For example, if MyError defines 38// 39// func (m MyError) Is(target error) bool { return target == fs.ErrExist } 40// 41// then Is(MyError{}, fs.ErrExist) returns true. See [syscall.Errno.Is] for 42// an example in the standard library. An Is method should only shallowly 43// compare err and the target and not call [Unwrap] on either. 44func Is(err, target error) bool { 45 if err == nil || target == nil { 46 return err == target 47 } 48 49 isComparable := reflectlite.TypeOf(target).Comparable() 50 return is(err, target, isComparable) 51} 52 53func is(err, target error, targetComparable bool) bool { 54 for { 55 if targetComparable && err == target { 56 return true 57 } 58 if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) { 59 return true 60 } 61 switch x := err.(type) { 62 case interface{ Unwrap() error }: 63 err = x.Unwrap() 64 if err == nil { 65 return false 66 } 67 case interface{ Unwrap() []error }: 68 for _, err := range x.Unwrap() { 69 if is(err, target, targetComparable) { 70 return true 71 } 72 } 73 return false 74 default: 75 return false 76 } 77 } 78} 79 80// As finds the first error in err's tree that matches target, and if one is found, sets 81// target to that error value and returns true. Otherwise, it returns false. 82// 83// The tree consists of err itself, followed by the errors obtained by repeatedly 84// calling its Unwrap() error or Unwrap() []error method. When err wraps multiple 85// errors, As examines err followed by a depth-first traversal of its children. 86// 87// An error matches target if the error's concrete value is assignable to the value 88// pointed to by target, or if the error has a method As(any) bool such that 89// As(target) returns true. In the latter case, the As method is responsible for 90// setting target. 91// 92// An error type might provide an As method so it can be treated as if it were a 93// different error type. 94// 95// As panics if target is not a non-nil pointer to either a type that implements 96// error, or to any interface type. 97func As(err error, target any) bool { 98 if err == nil { 99 return false 100 } 101 if target == nil { 102 panic("errors: target cannot be nil") 103 } 104 val := reflectlite.ValueOf(target) 105 typ := val.Type() 106 if typ.Kind() != reflectlite.Ptr || val.IsNil() { 107 panic("errors: target must be a non-nil pointer") 108 } 109 targetType := typ.Elem() 110 if targetType.Kind() != reflectlite.Interface && !targetType.Implements(errorType) { 111 panic("errors: *target must be interface or implement error") 112 } 113 return as(err, target, val, targetType) 114} 115 116func as(err error, target any, targetVal reflectlite.Value, targetType reflectlite.Type) bool { 117 for { 118 if reflectlite.TypeOf(err).AssignableTo(targetType) { 119 targetVal.Elem().Set(reflectlite.ValueOf(err)) 120 return true 121 } 122 if x, ok := err.(interface{ As(any) bool }); ok && x.As(target) { 123 return true 124 } 125 switch x := err.(type) { 126 case interface{ Unwrap() error }: 127 err = x.Unwrap() 128 if err == nil { 129 return false 130 } 131 case interface{ Unwrap() []error }: 132 for _, err := range x.Unwrap() { 133 if err == nil { 134 continue 135 } 136 if as(err, target, targetVal, targetType) { 137 return true 138 } 139 } 140 return false 141 default: 142 return false 143 } 144 } 145} 146 147var errorType = reflectlite.TypeOf((*error)(nil)).Elem() 148