Source file src/fmt/errors.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 fmt
     6  
     7  import (
     8  	"errors"
     9  	"internal/stringslite"
    10  	"slices"
    11  )
    12  
    13  // Errorf formats according to a format specifier and returns the string as a
    14  // value that satisfies error.
    15  //
    16  // If the format specifier includes a %w verb with an error operand,
    17  // the returned error will implement an Unwrap method returning the operand.
    18  // If there is more than one %w verb, the returned error will implement an
    19  // Unwrap method returning a []error containing all the %w operands in the
    20  // order they appear in the arguments.
    21  // It is invalid to supply the %w verb with an operand that does not implement
    22  // the error interface. The %w verb is otherwise a synonym for %v.
    23  func Errorf(format string, a ...any) (err error) {
    24  	// This function has been split in a somewhat unnatural way
    25  	// so that both it and the errors.New call can be inlined.
    26  	if err = errorf(format, a...); err != nil {
    27  		return err
    28  	}
    29  	// No formatting was needed. We can avoid some allocations and other work.
    30  	// See https://go.dev/cl/708836 for details.
    31  	return errors.New(format)
    32  }
    33  
    34  // errorf formats and returns an error value, or nil if no formatting is required.
    35  func errorf(format string, a ...any) error {
    36  	if len(a) == 0 && stringslite.IndexByte(format, '%') == -1 {
    37  		return nil
    38  	}
    39  	p := newPrinter()
    40  	p.wrapErrs = true
    41  	p.doPrintf(format, a)
    42  	s := string(p.buf)
    43  	var err error
    44  	switch len(p.wrappedErrs) {
    45  	case 0:
    46  		err = errors.New(s)
    47  	case 1:
    48  		w := &wrapError{msg: s}
    49  		w.err, _ = a[p.wrappedErrs[0]].(error)
    50  		err = w
    51  	default:
    52  		if p.reordered {
    53  			slices.Sort(p.wrappedErrs)
    54  		}
    55  		var errs []error
    56  		for i, argNum := range p.wrappedErrs {
    57  			if i > 0 && p.wrappedErrs[i-1] == argNum {
    58  				continue
    59  			}
    60  			if e, ok := a[argNum].(error); ok {
    61  				errs = append(errs, e)
    62  			}
    63  		}
    64  		err = &wrapErrors{s, errs}
    65  	}
    66  	p.free()
    67  	return err
    68  }
    69  
    70  type wrapError struct {
    71  	msg string
    72  	err error
    73  }
    74  
    75  func (e *wrapError) Error() string {
    76  	return e.msg
    77  }
    78  
    79  func (e *wrapError) Unwrap() error {
    80  	return e.err
    81  }
    82  
    83  type wrapErrors struct {
    84  	msg  string
    85  	errs []error
    86  }
    87  
    88  func (e *wrapErrors) Error() string {
    89  	return e.msg
    90  }
    91  
    92  func (e *wrapErrors) Unwrap() []error {
    93  	return e.errs
    94  }
    95  

View as plain text