]> Cypherpunks.ru repositories - gostls13.git/blob - src/errors/wrap.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / errors / wrap.go
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
5 package errors
6
7 import (
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].
17 func 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 [Unwrap]. When err wraps multiple errors, Is examines err followed by a
31 // 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.
44 func Is(err, target error) bool {
45         if target == nil {
46                 return err == target
47         }
48
49         isComparable := reflectlite.TypeOf(target).Comparable()
50         return is(err, target, isComparable)
51 }
52
53 func 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 [Unwrap]. When err wraps multiple errors, As examines err followed by a
85 // 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(interface{}) 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.
97 func 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
116 func 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
147 var errorType = reflectlite.TypeOf((*error)(nil)).Elem()