// Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package fmt import ( "errors" "internal/stringslite" "slices" ) // Errorf formats according to a format specifier and returns the string as a // value that satisfies error. // // If the format specifier includes a %w verb with an error operand, // the returned error will implement an Unwrap method returning the operand. // If there is more than one %w verb, the returned error will implement an // Unwrap method returning a []error containing all the %w operands in the // order they appear in the arguments. // It is invalid to supply the %w verb with an operand that does not implement // the error interface. The %w verb is otherwise a synonym for %v. func Errorf(format string, a ...any) (err error) { // This function has been split in a somewhat unnatural way // so that both it and the errors.New call can be inlined. if err = errorf(format, a...); err != nil { return err } // No formatting was needed. We can avoid some allocations and other work. // See https://go.dev/cl/708836 for details. return errors.New(format) } // errorf formats and returns an error value, or nil if no formatting is required. func errorf(format string, a ...any) error { if len(a) == 0 && stringslite.IndexByte(format, '%') == -1 { return nil } p := newPrinter() p.wrapErrs = true p.doPrintf(format, a) s := string(p.buf) var err error switch len(p.wrappedErrs) { case 0: err = errors.New(s) case 1: w := &wrapError{msg: s} w.err, _ = a[p.wrappedErrs[0]].(error) err = w default: if p.reordered { slices.Sort(p.wrappedErrs) } var errs []error for i, argNum := range p.wrappedErrs { if i > 0 && p.wrappedErrs[i-1] == argNum { continue } if e, ok := a[argNum].(error); ok { errs = append(errs, e) } } err = &wrapErrors{s, errs} } p.free() return err } type wrapError struct { msg string err error } func (e *wrapError) Error() string { return e.msg } func (e *wrapError) Unwrap() error { return e.err } type wrapErrors struct { msg string errs []error } func (e *wrapErrors) Error() string { return e.msg } func (e *wrapErrors) Unwrap() []error { return e.errs }