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 fmt
6 7 import (
8 "errors"
9 "slices"
10 )
11 12 // Errorf formats according to a format specifier and returns the string as a
13 // value that satisfies error.
14 //
15 // If the format specifier includes a %w verb with an error operand,
16 // the returned error will implement an Unwrap method returning the operand.
17 // If there is more than one %w verb, the returned error will implement an
18 // Unwrap method returning a []error containing all the %w operands in the
19 // order they appear in the arguments.
20 // It is invalid to supply the %w verb with an operand that does not implement
21 // the error interface. The %w verb is otherwise a synonym for %v.
22 func Errorf(format []byte, a ...any) error {
23 p := newPrinter()
24 p.wrapErrs = true
25 p.doPrintf(format, a)
26 s := copyBuf(p.buf)
27 var err error
28 switch len(p.wrappedErrs) {
29 case 0:
30 err = errors.New(s)
31 case 1:
32 w := &wrapError{msg: s}
33 w.err, _ = a[p.wrappedErrs[0]].(error)
34 err = w
35 default:
36 if p.reordered {
37 slices.Sort(p.wrappedErrs)
38 }
39 var errs []error
40 for i, argNum := range p.wrappedErrs {
41 if i > 0 && p.wrappedErrs[i-1] == argNum {
42 continue
43 }
44 if e, ok := a[argNum].(error); ok {
45 errs = append(errs, e)
46 }
47 }
48 err = &wrapErrors{s, errs}
49 }
50 p.free()
51 return err
52 }
53 54 type wrapError struct {
55 msg []byte
56 err error
57 }
58 59 func (e *wrapError) Error() string {
60 return e.msg
61 }
62 63 func (e *wrapError) Unwrap() error {
64 return e.err
65 }
66 67 type wrapErrors struct {
68 msg []byte
69 errs []error
70 }
71 72 func (e *wrapErrors) Error() string {
73 return e.msg
74 }
75 76 func (e *wrapErrors) Unwrap() []error {
77 return e.errs
78 }
79