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 fmt
6
7import (
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.
22func Errorf(format string, a ...any) error {
23	p := newPrinter()
24	p.wrapErrs = true
25	p.doPrintf(format, a)
26	s := string(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
54type wrapError struct {
55	msg string
56	err error
57}
58
59func (e *wrapError) Error() string {
60	return e.msg
61}
62
63func (e *wrapError) Unwrap() error {
64	return e.err
65}
66
67type wrapErrors struct {
68	msg  string
69	errs []error
70}
71
72func (e *wrapErrors) Error() string {
73	return e.msg
74}
75
76func (e *wrapErrors) Unwrap() []error {
77	return e.errs
78}
79