]> Cypherpunks.ru repositories - gostls13.git/commitdiff
errors, fmt: revert rejected changes for Go 1.13
authorDamien Neil <dneil@google.com>
Mon, 13 May 2019 21:51:55 +0000 (14:51 -0700)
committerDamien Neil <dneil@google.com>
Wed, 15 May 2019 19:53:15 +0000 (19:53 +0000)
Reverts the following changes:

  https://go.googlesource.com/go/+/1f90d081391d4f5911960fd28d81d7ea5e554a8f
  https://go.googlesource.com/go/+/8bf18b56a47a98b9dd2fa03beb358312237a8c76
  https://go.googlesource.com/go/+/5402854c3557f87fa2741a52ffc15dfb1ef333cc
  https://go.googlesource.com/go/+/37f84817247d3b8e687a701ccb0d6bc7ffe3cb78
  https://go.googlesource.com/go/+/6be6f114e0d483a233101a67c9644cd72bd3ae7a

Partially reverts the followinng change, removing the errors.Opaque
function and the errors.Wrapper type definition:

  https://go.googlesource.com/go/+/62f5e8156ef56fa61e6af56f4ccc633bde1a9120

Updates documentation referencing the Wrapper type.

Change-Id: Ia622883e39cafb06809853e3fd90b21441124534
Reviewed-on: https://go-review.googlesource.com/c/go/+/176997
Run-TryBot: Damien Neil <dneil@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
15 files changed:
src/errors/errors.go
src/errors/format.go [deleted file]
src/errors/frame.go [deleted file]
src/errors/frame_test.go [deleted file]
src/errors/wrap.go
src/errors/wrap_test.go
src/fmt/doc.go
src/fmt/errors.go [deleted file]
src/fmt/errors_test.go [deleted file]
src/fmt/format.go
src/fmt/format_example_test.go [deleted file]
src/fmt/print.go
src/go/build/deps_test.go
src/internal/errinternal/errinternal.go [deleted file]
src/internal/oserror/errors_test.go

index 51175b13c8710609f3b8ce7333e895ba654ecd5a..b8a46921be00e8d872ceccd036e6a2aff4b04acf 100644 (file)
@@ -5,46 +5,16 @@
 // Package errors implements functions to manipulate errors.
 package errors
 
-import (
-       "internal/errinternal"
-       "runtime"
-)
-
 // New returns an error that formats as the given text.
-//
-// The returned error contains a Frame set to the caller's location and
-// implements Formatter to show this information when printed with details.
 func New(text string) error {
-       // Inline call to errors.Callers to improve performance.
-       var s Frame
-       runtime.Callers(2, s.frames[:])
-       return &errorString{text, nil, s}
-}
-
-func init() {
-       errinternal.NewError = func(text string, err error) error {
-               var s Frame
-               runtime.Callers(3, s.frames[:])
-               return &errorString{text, err, s}
-       }
+       return &errorString{text}
 }
 
 // errorString is a trivial implementation of error.
 type errorString struct {
-       s     string
-       err   error
-       frame Frame
+       s string
 }
 
 func (e *errorString) Error() string {
-       if e.err != nil {
-               return e.s + ": " + e.err.Error()
-       }
        return e.s
 }
-
-func (e *errorString) FormatError(p Printer) (next error) {
-       p.Print(e.s)
-       e.frame.Format(p)
-       return e.err
-}
diff --git a/src/errors/format.go b/src/errors/format.go
deleted file mode 100644 (file)
index 12deed3..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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 errors
-
-// A Formatter formats error messages.
-type Formatter interface {
-       error
-
-       // FormatError prints the receiver's first error and returns the next error in
-       // the error chain, if any.
-       FormatError(p Printer) (next error)
-}
-
-// A Printer formats error messages.
-//
-// The most common implementation of Printer is the one provided by package fmt
-// during Printf. Localization packages such as golang.org/x/text/message
-// typically provide their own implementations.
-type Printer interface {
-       // Print appends args to the message output.
-       Print(args ...interface{})
-
-       // Printf writes a formatted string.
-       Printf(format string, args ...interface{})
-
-       // Detail reports whether error detail is requested.
-       // After the first call to Detail, all text written to the Printer
-       // is formatted as additional detail, or ignored when
-       // detail has not been requested.
-       // If Detail returns false, the caller can avoid printing the detail at all.
-       Detail() bool
-}
diff --git a/src/errors/frame.go b/src/errors/frame.go
deleted file mode 100644 (file)
index 487092f..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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 errors
-
-import (
-       "runtime"
-)
-
-// A Frame contains part of a call stack.
-type Frame struct {
-       frames [1]uintptr
-}
-
-// Caller returns a Frame that describes a frame on the caller's stack.
-// The argument skip is the number of frames to skip over.
-// Caller(0) returns the frame for the caller of Caller.
-func Caller(skip int) Frame {
-       var s Frame
-       runtime.Callers(skip+2, s.frames[:])
-       return s
-}
-
-// location reports the file, line, and function of a frame.
-//
-// The returned function may be "" even if file and line are not.
-func (f Frame) location() (function, file string, line int) {
-       frames := runtime.CallersFrames(f.frames[:])
-       fr, _ := frames.Next()
-       return fr.Function, fr.File, fr.Line
-}
-
-// Format prints the stack as error detail.
-// It should be called from an error's Format implementation,
-// before printing any other error detail.
-func (f Frame) Format(p Printer) {
-       if p.Detail() {
-               function, file, line := f.location()
-               if function != "" {
-                       p.Printf("%s\n    ", function)
-               }
-               if file != "" {
-                       p.Printf("%s:%d\n", file, line)
-               }
-       }
-}
diff --git a/src/errors/frame_test.go b/src/errors/frame_test.go
deleted file mode 100644 (file)
index ba08166..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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 errors_test
-
-import (
-       "bytes"
-       "errors"
-       "fmt"
-       "math/big"
-       "regexp"
-       "strings"
-       "testing"
-)
-
-func TestFrame(t *testing.T) {
-
-       // Extra line
-       got := fmt.Sprintf("%+v", errors.New("Test"))
-       got = got[strings.Index(got, "Test"):]
-       const want = "^Test:" +
-               "\n    errors_test.TestFrame" +
-               "\n        .*/errors/frame_test.go:20$"
-       ok, err := regexp.MatchString(want, got)
-       if err != nil {
-               t.Fatal(err)
-       }
-       if !ok {
-               t.Errorf("\n got %v;\nwant %v", got, want)
-       }
-}
-
-type myType struct{}
-
-func (myType) Format(s fmt.State, v rune) {
-       s.Write(bytes.Repeat([]byte("Hi! "), 10))
-}
-
-func BenchmarkNew(b *testing.B) {
-       for i := 0; i < b.N; i++ {
-               _ = errors.New("new error")
-       }
-}
-
-func BenchmarkErrorf(b *testing.B) {
-       err := errors.New("foo")
-       args := func(a ...interface{}) []interface{} { return a }
-       benchCases := []struct {
-               name   string
-               format string
-               args   []interface{}
-       }{
-               {"no_format", "msg: %v", args(err)},
-               {"with_format", "failed %d times: %v", args(5, err)},
-               {"method: mytype", "pi %s %v: %v", args("myfile.go", myType{}, err)},
-               {"method: number", "pi %s %d: %v", args("myfile.go", big.NewInt(5), err)},
-       }
-       for _, bc := range benchCases {
-               b.Run(bc.name, func(b *testing.B) {
-                       for i := 0; i < b.N; i++ {
-                               _ = fmt.Errorf(bc.format, bc.args...)
-                       }
-               })
-       }
-}
index b53caa6fc9a137ef75c26c7fb58a419d8ab9f57c..62332b1a8897bff56bcceb9f328c717c6359c9c7 100644 (file)
@@ -8,35 +8,12 @@ import (
        "internal/reflectlite"
 )
 
-// A Wrapper provides context around another error.
-type Wrapper interface {
-       // Unwrap returns the next error in the error chain.
-       // If there is no next error, Unwrap returns nil.
-       Unwrap() error
-}
-
-// Opaque returns an error with the same error formatting as err
-// but that does not match err and cannot be unwrapped.
-func Opaque(err error) error {
-       return noWrapper{err}
-}
-
-type noWrapper struct {
-       error
-}
-
-func (e noWrapper) FormatError(p Printer) (next error) {
-       if f, ok := e.error.(Formatter); ok {
-               return f.FormatError(p)
-       }
-       p.Print(e.error)
-       return nil
-}
-
 // Unwrap returns the result of calling the Unwrap method on err, if err
 // implements Wrapper. Otherwise, Unwrap returns nil.
 func Unwrap(err error) error {
-       u, ok := err.(Wrapper)
+       u, ok := err.(interface {
+               Unwrap() error
+       })
        if !ok {
                return nil
        }
index f8e907cff71b8716a6f63c50786faecae8012d73..2055316756e427f752202b28985ef6c058026dfc 100644 (file)
@@ -5,7 +5,6 @@
 package errors_test
 
 import (
-       "bytes"
        "errors"
        "fmt"
        "os"
@@ -16,8 +15,6 @@ func TestIs(t *testing.T) {
        err1 := errors.New("1")
        erra := wrapped{"wrap 2", err1}
        errb := wrapped{"wrap 3", erra}
-       erro := errors.Opaque(err1)
-       errco := wrapped{"opaque", erro}
 
        err3 := errors.New("3")
 
@@ -35,9 +32,6 @@ func TestIs(t *testing.T) {
                {err1, err1, true},
                {erra, err1, true},
                {errb, err1, true},
-               {errco, erro, true},
-               {errco, err1, false},
-               {erro, erro, true},
                {err1, err3, false},
                {erra, err3, false},
                {errb, err3, false},
@@ -45,8 +39,6 @@ func TestIs(t *testing.T) {
                {poser, err3, true},
                {poser, erra, false},
                {poser, errb, false},
-               {poser, erro, false},
-               {poser, errco, false},
                {errorUncomparable{}, errorUncomparable{}, true},
                {errorUncomparable{}, &errorUncomparable{}, false},
                {&errorUncomparable{}, errorUncomparable{}, true},
@@ -107,10 +99,6 @@ func TestAs(t *testing.T) {
                errF,
                &errP,
                true,
-       }, {
-               errors.Opaque(errT),
-               &errT,
-               false,
        }, {
                errorT{},
                &errP,
@@ -187,7 +175,6 @@ func TestAsValidation(t *testing.T) {
 func TestUnwrap(t *testing.T) {
        err1 := errors.New("1")
        erra := wrapped{"wrap 2", err1}
-       erro := errors.Opaque(err1)
 
        testCases := []struct {
                err  error
@@ -198,9 +185,6 @@ func TestUnwrap(t *testing.T) {
                {err1, nil},
                {erra, err1},
                {wrapped{"wrap 3", erra}, erra},
-
-               {erro, nil},
-               {wrapped{"opaque", erro}, erro},
        }
        for _, tc := range testCases {
                if got := errors.Unwrap(tc.err); got != tc.want {
@@ -209,39 +193,6 @@ func TestUnwrap(t *testing.T) {
        }
 }
 
-func TestOpaque(t *testing.T) {
-       someError := errors.New("some error")
-       testCases := []struct {
-               err  error
-               next error
-       }{
-               {errorT{}, nil},
-               {wrapped{"b", nil}, nil},
-               {wrapped{"c", someError}, someError},
-       }
-       for _, tc := range testCases {
-               t.Run("", func(t *testing.T) {
-                       opaque := errors.Opaque(tc.err)
-
-                       f, ok := opaque.(errors.Formatter)
-                       if !ok {
-                               t.Fatal("Opaque error does not implement Formatter")
-                       }
-                       var p printer
-                       next := f.FormatError(&p)
-                       if next != tc.next {
-                               t.Errorf("next was %v; want %v", next, tc.next)
-                       }
-                       if got, want := p.buf.String(), tc.err.Error(); got != want {
-                               t.Errorf("error was %q; want %q", got, want)
-                       }
-                       if got := errors.Unwrap(opaque); got != nil {
-                               t.Errorf("Unwrap returned non-nil error (%v)", got)
-                       }
-               })
-       }
-}
-
 type errorT struct{}
 
 func (errorT) Error() string { return "errorT" }
@@ -255,18 +206,6 @@ func (e wrapped) Error() string { return e.msg }
 
 func (e wrapped) Unwrap() error { return e.err }
 
-func (e wrapped) FormatError(p errors.Printer) error {
-       p.Print(e.msg)
-       return e.err
-}
-
-type printer struct {
-       errors.Printer
-       buf bytes.Buffer
-}
-
-func (p *printer) Print(args ...interface{}) { fmt.Fprint(&p.buf, args...) }
-
 type errorUncomparable struct {
        f []string
 }
index b784399e0d920962f844db490748c4b608216c70..a7115809d3dcf7d82c99ace45f55d4a950c7bb5a 100644 (file)
        1. If the operand is a reflect.Value, the operand is replaced by the
        concrete value that it holds, and printing continues with the next rule.
 
-       2. If an operand implements the Formatter interface, and not
-       errors.Formatter, it will be invoked. Formatter provides fine
-       control of formatting.
+       2. If an operand implements the Formatter interface, it will
+       be invoked. Formatter provides fine control of formatting.
 
        3. If the %v verb is used with the # flag (%#v) and the operand
        implements the GoStringer interface, that will be invoked.
 
        If the format (which is implicitly %v for Println etc.) is valid
-       for a string (%s %q %v %x %X), the following three rules apply:
+       for a string (%s %q %v %x %X), the following two rules apply:
 
-       4. If an operand implements errors.Formatter, the FormatError
-       method will be invoked with an errors.Printer to print the error.
-       If the %v flag is used with the + flag (%+v), the Detail method
-       of the Printer will return true and the error will be formatted
-       as a detailed error message. Otherwise the printed string will
-       be formatted as required by the verb (if any).
-
-       5. If an operand implements the error interface, the Error method
+       4. If an operand implements the error interface, the Error method
        will be invoked to convert the object to a string, which will then
        be formatted as required by the verb (if any).
 
-       6. If an operand implements method String() string, that method
+       5. If an operand implements method String() string, that method
        will be invoked to convert the object to a string, which will then
        be formatted as required by the verb (if any).
 
diff --git a/src/fmt/errors.go b/src/fmt/errors.go
deleted file mode 100644 (file)
index 4dcd01b..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-// 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/errinternal"
-       "strings"
-)
-
-// Errorf formats according to a format specifier and returns the string as a
-// value that satisfies error.
-//
-// The returned error includes the file and line number of the caller when
-// formatted with additional detail enabled. If the last argument is an error
-// the returned error's Format method will return it if the format string ends
-// with ": %s", ": %v", or ": %w". If the last argument is an error and the
-// format string ends with ": %w", the returned error implements errors.Wrapper
-// with an Unwrap method returning it.
-func Errorf(format string, a ...interface{}) error {
-       err, wrap := lastError(format, a)
-       if err == nil {
-               return errinternal.NewError(Sprintf(format, a...), nil)
-       }
-
-       // TODO: this is not entirely correct. The error value could be
-       // printed elsewhere in format if it mixes numbered with unnumbered
-       // substitutions. With relatively small changes to doPrintf we can
-       // have it optionally ignore extra arguments and pass the argument
-       // list in its entirety.
-       msg := Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...)
-       if wrap {
-               return &wrapError{msg, err, errors.Caller(1)}
-       }
-       return errinternal.NewError(msg, err)
-}
-
-func lastError(format string, a []interface{}) (err error, wrap bool) {
-       wrap = strings.HasSuffix(format, ": %w")
-       if !wrap &&
-               !strings.HasSuffix(format, ": %s") &&
-               !strings.HasSuffix(format, ": %v") {
-               return nil, false
-       }
-
-       if len(a) == 0 {
-               return nil, false
-       }
-
-       err, ok := a[len(a)-1].(error)
-       if !ok {
-               return nil, false
-       }
-
-       return err, wrap
-}
-
-type noWrapError struct {
-       msg   string
-       err   error
-       frame errors.Frame
-}
-
-func (e *noWrapError) Error() string {
-       return Sprint(e)
-}
-
-func (e *noWrapError) FormatError(p errors.Printer) (next error) {
-       p.Print(e.msg)
-       e.frame.Format(p)
-       return e.err
-}
-
-type wrapError struct {
-       msg   string
-       err   error
-       frame errors.Frame
-}
-
-func (e *wrapError) Error() string {
-       return Sprint(e)
-}
-
-func (e *wrapError) FormatError(p errors.Printer) (next error) {
-       p.Print(e.msg)
-       e.frame.Format(p)
-       return e.err
-}
-
-func (e *wrapError) Unwrap() error {
-       return e.err
-}
-
-func fmtError(p *pp, verb rune, err error) (handled bool) {
-       var (
-               sep = " " // separator before next error
-               w   = p   // print buffer where error text is written
-       )
-       switch {
-       // Note that this switch must match the preference order
-       // for ordinary string printing (%#v before %+v, and so on).
-
-       case p.fmt.sharpV:
-               if stringer, ok := p.arg.(GoStringer); ok {
-                       // Print the result of GoString unadorned.
-                       p.fmt.fmtS(stringer.GoString())
-                       return true
-               }
-               return false
-
-       case p.fmt.plusV:
-               sep = "\n  - "
-               w.fmt.fmtFlags = fmtFlags{plusV: p.fmt.plusV} // only keep detail flag
-
-               // The width or precision of a detailed view could be the number of
-               // errors to print from a list.
-
-       default:
-               // Use an intermediate buffer in the rare cases that precision,
-               // truncation, or one of the alternative verbs (q, x, and X) are
-               // specified.
-               switch verb {
-               case 's', 'v':
-                       if (!w.fmt.widPresent || w.fmt.wid == 0) && !w.fmt.precPresent {
-                               break
-                       }
-                       fallthrough
-               case 'q', 'x', 'X':
-                       w = newPrinter()
-                       defer w.free()
-               default:
-                       return false
-               }
-       }
-
-loop:
-       for {
-               w.fmt.inDetail = false
-               switch v := err.(type) {
-               case errors.Formatter:
-                       err = v.FormatError((*errPP)(w))
-               case Formatter:
-                       if w.fmt.plusV {
-                               v.Format((*errPPState)(w), 'v') // indent new lines
-                       } else {
-                               v.Format(w, 'v') // do not indent new lines
-                       }
-                       break loop
-               default:
-                       w.fmtString(v.Error(), 's')
-                       break loop
-               }
-               if err == nil {
-                       break
-               }
-               if w.fmt.needColon || !p.fmt.plusV {
-                       w.buf.writeByte(':')
-                       w.fmt.needColon = false
-               }
-               w.buf.writeString(sep)
-               w.fmt.inDetail = false
-               w.fmt.needNewline = false
-       }
-
-       if w != p {
-               p.fmtString(string(w.buf), verb)
-       }
-       return true
-}
-
-var detailSep = []byte("\n    ")
-
-// errPPState wraps a pp to implement State with indentation. It is used
-// for errors implementing fmt.Formatter.
-type errPPState pp
-
-func (p *errPPState) Width() (wid int, ok bool)      { return (*pp)(p).Width() }
-func (p *errPPState) Precision() (prec int, ok bool) { return (*pp)(p).Precision() }
-func (p *errPPState) Flag(c int) bool                { return (*pp)(p).Flag(c) }
-
-func (p *errPPState) Write(b []byte) (n int, err error) {
-       if p.fmt.plusV {
-               if len(b) == 0 {
-                       return 0, nil
-               }
-               if p.fmt.inDetail && p.fmt.needColon {
-                       p.fmt.needNewline = true
-                       if b[0] == '\n' {
-                               b = b[1:]
-                       }
-               }
-               k := 0
-               for i, c := range b {
-                       if p.fmt.needNewline {
-                               if p.fmt.inDetail && p.fmt.needColon {
-                                       p.buf.writeByte(':')
-                                       p.fmt.needColon = false
-                               }
-                               p.buf.write(detailSep)
-                               p.fmt.needNewline = false
-                       }
-                       if c == '\n' {
-                               p.buf.write(b[k:i])
-                               k = i + 1
-                               p.fmt.needNewline = true
-                       }
-               }
-               p.buf.write(b[k:])
-               if !p.fmt.inDetail {
-                       p.fmt.needColon = true
-               }
-       } else if !p.fmt.inDetail {
-               p.buf.write(b)
-       }
-       return len(b), nil
-
-}
-
-// errPP wraps a pp to implement an errors.Printer.
-type errPP pp
-
-func (p *errPP) Print(args ...interface{}) {
-       if !p.fmt.inDetail || p.fmt.plusV {
-               Fprint((*errPPState)(p), args...)
-       }
-}
-
-func (p *errPP) Printf(format string, args ...interface{}) {
-       if !p.fmt.inDetail || p.fmt.plusV {
-               Fprintf((*errPPState)(p), format, args...)
-       }
-}
-
-func (p *errPP) Detail() bool {
-       p.fmt.inDetail = true
-       return p.fmt.plusV
-}
diff --git a/src/fmt/errors_test.go b/src/fmt/errors_test.go
deleted file mode 100644 (file)
index 39f247e..0000000
+++ /dev/null
@@ -1,576 +0,0 @@
-// 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_test
-
-import (
-       "errors"
-       "fmt"
-       "io"
-       "os"
-       "path"
-       "reflect"
-       "regexp"
-       "strconv"
-       "strings"
-       "testing"
-)
-
-func TestErrorf(t *testing.T) {
-       chained := &wrapped{"chained", nil}
-       chain := func(s ...string) (a []string) {
-               for _, s := range s {
-                       a = append(a, cleanPath(s))
-               }
-               return a
-       }
-       noArgsWrap := "no args: %w" // avoid vet check
-       testCases := []struct {
-               got  error
-               want []string
-       }{{
-               fmt.Errorf("no args"),
-               chain("no args/path.TestErrorf/path.go:xxx"),
-       }, {
-               fmt.Errorf(noArgsWrap),
-               chain("no args: %!w(MISSING)/path.TestErrorf/path.go:xxx"),
-       }, {
-               fmt.Errorf("nounwrap: %s", "simple"),
-               chain(`nounwrap: simple/path.TestErrorf/path.go:xxx`),
-       }, {
-               fmt.Errorf("nounwrap: %v", "simple"),
-               chain(`nounwrap: simple/path.TestErrorf/path.go:xxx`),
-       }, {
-               fmt.Errorf("%s failed: %v", "foo", chained),
-               chain("foo failed/path.TestErrorf/path.go:xxx",
-                       "chained/somefile.go:xxx"),
-       }, {
-               fmt.Errorf("no wrap: %s", chained),
-               chain("no wrap/path.TestErrorf/path.go:xxx",
-                       "chained/somefile.go:xxx"),
-       }, {
-               fmt.Errorf("%s failed: %w", "foo", chained),
-               chain("wraps:foo failed/path.TestErrorf/path.go:xxx",
-                       "chained/somefile.go:xxx"),
-       }, {
-               fmt.Errorf("nowrapv: %v", chained),
-               chain("nowrapv/path.TestErrorf/path.go:xxx",
-                       "chained/somefile.go:xxx"),
-       }, {
-               fmt.Errorf("wrapw: %w", chained),
-               chain("wraps:wrapw/path.TestErrorf/path.go:xxx",
-                       "chained/somefile.go:xxx"),
-       }, {
-               fmt.Errorf("not wrapped: %+v", chained),
-               chain("not wrapped: chained: somefile.go:123/path.TestErrorf/path.go:xxx"),
-       }}
-       for i, tc := range testCases {
-               t.Run(strconv.Itoa(i)+"/"+path.Join(tc.want...), func(t *testing.T) {
-                       got := errToParts(tc.got)
-                       if !reflect.DeepEqual(got, tc.want) {
-                               t.Errorf("Format:\n got: %+q\nwant: %+q", got, tc.want)
-                       }
-
-                       gotStr := tc.got.Error()
-                       wantStr := fmt.Sprint(tc.got)
-                       if gotStr != wantStr {
-                               t.Errorf("Error:\n got: %+q\nwant: %+q", gotStr, wantStr)
-                       }
-               })
-       }
-}
-
-func TestErrorFormatter(t *testing.T) {
-       testCases := []struct {
-               err    error
-               fmt    string
-               want   string
-               regexp bool
-       }{{
-               err: errors.New("foo"),
-               fmt: "%+v",
-               want: "foo:" +
-                       "\n    fmt_test.TestErrorFormatter" +
-                       "\n        .+/fmt/errors_test.go:\\d\\d",
-               regexp: true,
-       }, {
-               err:  &wrapped{"simple", nil},
-               fmt:  "%s",
-               want: "simple",
-       }, {
-               err:  &wrapped{"can't adumbrate elephant", outOfPeanuts{}},
-               fmt:  "%s",
-               want: "can't adumbrate elephant: out of peanuts",
-       }, {
-               err:  &wrapped{"a", &wrapped{"b", &wrapped{"c", nil}}},
-               fmt:  "%s",
-               want: "a: b: c",
-       }, {
-               err: &wrapped{"simple", nil},
-               fmt: "%+v",
-               want: "simple:" +
-                       "\n    somefile.go:123",
-       }, {
-               err: &wrapped{"can't adumbrate elephant", outOfPeanuts{}},
-               fmt: "%+v",
-               want: "can't adumbrate elephant:" +
-                       "\n    somefile.go:123" +
-                       "\n  - out of peanuts:" +
-                       "\n    the elephant is on strike" +
-                       "\n    and the 12 monkeys" +
-                       "\n    are laughing",
-       }, {
-               err:  &wrapped{"simple", nil},
-               fmt:  "%#v",
-               want: "&fmt_test.wrapped{msg:\"simple\", err:error(nil)}",
-       }, {
-               err:  &notAFormatterError{},
-               fmt:  "%+v",
-               want: "not a formatter",
-       }, {
-               err: &wrapped{"wrap", &notAFormatterError{}},
-               fmt: "%+v",
-               want: "wrap:" +
-                       "\n    somefile.go:123" +
-                       "\n  - not a formatter",
-       }, {
-               err: &withFrameAndMore{frame: errors.Caller(0)},
-               fmt: "%+v",
-               want: "something:" +
-                       "\n    fmt_test.TestErrorFormatter" +
-                       "\n        .+/fmt/errors_test.go:\\d\\d\\d" +
-                       "\n    something more",
-               regexp: true,
-       }, {
-               err:  fmtTwice("Hello World!"),
-               fmt:  "%#v",
-               want: "2 times Hello World!",
-       }, {
-               err:  &wrapped{"fallback", os.ErrNotExist},
-               fmt:  "%s",
-               want: "fallback: file does not exist",
-       }, {
-               err: &wrapped{"fallback", os.ErrNotExist},
-               fmt: "%+v",
-               // Note: no colon after the last error, as there are no details.
-               want: "fallback:" +
-                       "\n    somefile.go:123" +
-                       "\n  - file does not exist:" +
-                       "\n    .*" +
-                       "\n        .+.go:\\d+",
-               regexp: true,
-       }, {
-               err: &wrapped{"outer",
-                       errors.Opaque(&wrapped{"mid",
-                               &wrapped{"inner", nil}})},
-               fmt:  "%s",
-               want: "outer: mid: inner",
-       }, {
-               err: &wrapped{"outer",
-                       errors.Opaque(&wrapped{"mid",
-                               &wrapped{"inner", nil}})},
-               fmt: "%+v",
-               want: "outer:" +
-                       "\n    somefile.go:123" +
-                       "\n  - mid:" +
-                       "\n    somefile.go:123" +
-                       "\n  - inner:" +
-                       "\n    somefile.go:123",
-       }, {
-               err:  &wrapped{"new style", formatError("old style")},
-               fmt:  "%v",
-               want: "new style: old style",
-       }, {
-               err:  &wrapped{"new style", formatError("old style")},
-               fmt:  "%q",
-               want: `"new style: old style"`,
-       }, {
-               err: &wrapped{"new style", formatError("old style")},
-               fmt: "%+v",
-               // Note the extra indentation.
-               // Colon for old style error is rendered by the fmt.Formatter
-               // implementation of the old-style error.
-               want: "new style:" +
-                       "\n    somefile.go:123" +
-                       "\n  - old style:" +
-                       "\n    otherfile.go:456",
-       }, {
-               err:  &wrapped{"simple", nil},
-               fmt:  "%-12s",
-               want: "simple      ",
-       }, {
-               // Don't use formatting flags for detailed view.
-               err: &wrapped{"simple", nil},
-               fmt: "%+12v",
-               want: "simple:" +
-                       "\n    somefile.go:123",
-       }, {
-               err:  &wrapped{"can't adumbrate elephant", outOfPeanuts{}},
-               fmt:  "%+50s",
-               want: "          can't adumbrate elephant: out of peanuts",
-       }, {
-               err:  &wrapped{"café", nil},
-               fmt:  "%q",
-               want: `"café"`,
-       }, {
-               err:  &wrapped{"café", nil},
-               fmt:  "%+q",
-               want: `"caf\u00e9"`,
-       }, {
-               err:  &wrapped{"simple", nil},
-               fmt:  "% x",
-               want: "73 69 6d 70 6c 65",
-       }, {
-               err: &wrapped{"msg with\nnewline",
-                       &wrapped{"and another\none", nil}},
-               fmt: "%s",
-               want: "msg with" +
-                       "\nnewline: and another" +
-                       "\none",
-       }, {
-               err: &wrapped{"msg with\nnewline",
-                       &wrapped{"and another\none", nil}},
-               fmt: "%+v",
-               want: "msg with" +
-                       "\n    newline:" +
-                       "\n    somefile.go:123" +
-                       "\n  - and another" +
-                       "\n    one:" +
-                       "\n    somefile.go:123",
-       }, {
-               err: wrapped{"", wrapped{"inner message", nil}},
-               fmt: "%+v",
-               want: "somefile.go:123" +
-                       "\n  - inner message:" +
-                       "\n    somefile.go:123",
-       }, {
-               err:  detail{"empty detail", "", nil},
-               fmt:  "%s",
-               want: "empty detail",
-       }, {
-               err:  detail{"empty detail", "", nil},
-               fmt:  "%+v",
-               want: "empty detail",
-       }, {
-               err:  detail{"newline at start", "\nextra", nil},
-               fmt:  "%s",
-               want: "newline at start",
-       }, {
-               err: detail{"newline at start", "\n extra", nil},
-               fmt: "%+v",
-               want: "newline at start:" +
-                       "\n     extra",
-       }, {
-               err: detail{"newline at start", "\nextra",
-                       detail{"newline at start", "\nmore", nil}},
-               fmt: "%+v",
-               want: "newline at start:" +
-                       "\n    extra" +
-                       "\n  - newline at start:" +
-                       "\n    more",
-       }, {
-               err: detail{"two newlines at start", "\n\nextra",
-                       detail{"two newlines at start", "\n\nmore", nil}},
-               fmt: "%+v",
-               want: "two newlines at start:" +
-                       "\n    " + // note the explicit space
-                       "\n    extra" +
-                       "\n  - two newlines at start:" +
-                       "\n    " +
-                       "\n    more",
-       }, {
-               err:  &detail{"single newline", "\n", nil},
-               fmt:  "%+v",
-               want: "single newline",
-       }, {
-               err: &detail{"single newline", "\n",
-                       &detail{"single newline", "\n", nil}},
-               fmt: "%+v",
-               want: "single newline:" +
-                       "\n  - single newline",
-       }, {
-               err: &detail{"newline at end", "detail\n", nil},
-               fmt: "%+v",
-               want: "newline at end:" +
-                       "\n    detail",
-       }, {
-               err: &detail{"newline at end", "detail\n",
-                       &detail{"newline at end", "detail\n", nil}},
-               fmt: "%+v",
-               want: "newline at end:" +
-                       "\n    detail" +
-                       "\n  - newline at end:" +
-                       "\n    detail",
-       }, {
-               err: &detail{"two newlines at end", "detail\n\n",
-                       &detail{"two newlines at end", "detail\n\n", nil}},
-               fmt: "%+v",
-               want: "two newlines at end:" +
-                       "\n    detail" +
-                       "\n    " +
-                       "\n  - two newlines at end:" +
-                       "\n    detail" +
-                       "\n    ", // note the additional space
-       }, {
-               err:  nil,
-               fmt:  "%+v",
-               want: "<nil>",
-       }, {
-               err:  (*wrapped)(nil),
-               fmt:  "%+v",
-               want: "<nil>",
-       }, {
-               err:  &wrapped{"simple", nil},
-               fmt:  "%T",
-               want: "*fmt_test.wrapped",
-       }, {
-               err:  &wrapped{"simple", nil},
-               fmt:  "%🤪",
-               want: "&{%!🤪(string=simple) <nil>}",
-       }, {
-               err:  formatError("use fmt.Formatter"),
-               fmt:  "%#v",
-               want: "use fmt.Formatter",
-       }, {
-               err: wrapped{"using errors.Formatter",
-                       formatError("use fmt.Formatter")},
-               fmt:  "%#v",
-               want: "fmt_test.wrapped{msg:\"using errors.Formatter\", err:\"use fmt.Formatter\"}",
-       }, {
-               err:  fmtTwice("%s %s", "ok", panicValue{}),
-               fmt:  "%s",
-               want: "ok %!s(PANIC=String method: panic)/ok %!s(PANIC=String method: panic)",
-       }, {
-               err:  fmtTwice("%o %s", panicValue{}, "ok"),
-               fmt:  "%s",
-               want: "{} ok/{} ok",
-       }, {
-               err:  intError(4),
-               fmt:  "%v",
-               want: "error 4",
-       }, {
-               err:  intError(4),
-               fmt:  "%d",
-               want: "4",
-       }, {
-               err:  intError(4),
-               fmt:  "%🤪",
-               want: "%!🤪(fmt_test.intError=4)",
-       }}
-       for i, tc := range testCases {
-               t.Run(fmt.Sprintf("%d/%s", i, tc.fmt), func(t *testing.T) {
-                       got := fmt.Sprintf(tc.fmt, tc.err)
-                       var ok bool
-                       if tc.regexp {
-                               var err error
-                               ok, err = regexp.MatchString(tc.want+"$", got)
-                               if err != nil {
-                                       t.Fatal(err)
-                               }
-                       } else {
-                               ok = got == tc.want
-                       }
-                       if !ok {
-                               t.Errorf("\n got: %q\nwant: %q", got, tc.want)
-                       }
-               })
-       }
-}
-
-func TestSameType(t *testing.T) {
-       err0 := errors.New("inner")
-       want := fmt.Sprintf("%T", err0)
-
-       err := fmt.Errorf("foo: %v", err0)
-       if got := fmt.Sprintf("%T", err); got != want {
-               t.Errorf("got %v; want %v", got, want)
-       }
-
-       err = fmt.Errorf("foo %s", "bar")
-       if got := fmt.Sprintf("%T", err); got != want {
-               t.Errorf("got %v; want %v", got, want)
-       }
-}
-
-var _ errors.Formatter = wrapped{}
-
-type wrapped struct {
-       msg string
-       err error
-}
-
-func (e wrapped) Error() string { return fmt.Sprint(e) }
-
-func (e wrapped) FormatError(p errors.Printer) (next error) {
-       p.Print(e.msg)
-       p.Detail()
-       p.Print("somefile.go:123")
-       return e.err
-}
-
-var _ errors.Formatter = outOfPeanuts{}
-
-type outOfPeanuts struct{}
-
-func (e outOfPeanuts) Error() string { return fmt.Sprint(e) }
-
-func (e outOfPeanuts) Format(fmt.State, rune) {
-       panic("should never be called by one of the tests")
-}
-
-func (outOfPeanuts) FormatError(p errors.Printer) (next error) {
-       p.Printf("out of %s", "peanuts")
-       p.Detail()
-       p.Print("the elephant is on strike\n")
-       p.Printf("and the %d monkeys\nare laughing", 12)
-       return nil
-}
-
-type withFrameAndMore struct {
-       frame errors.Frame
-}
-
-func (e *withFrameAndMore) Error() string { return fmt.Sprint(e) }
-
-func (e *withFrameAndMore) FormatError(p errors.Printer) (next error) {
-       p.Print("something")
-       if p.Detail() {
-               e.frame.Format(p)
-               p.Print("something more")
-       }
-       return nil
-}
-
-type notAFormatterError struct{}
-
-func (e notAFormatterError) Error() string { return "not a formatter" }
-
-type detail struct {
-       msg    string
-       detail string
-       next   error
-}
-
-func (e detail) Error() string { return fmt.Sprint(e) }
-
-func (e detail) FormatError(p errors.Printer) (next error) {
-       p.Print(e.msg)
-       p.Detail()
-       p.Print(e.detail)
-       return e.next
-}
-
-type intError int
-
-func (e intError) Error() string { return fmt.Sprint(e) }
-
-func (e wrapped) Format(w fmt.State, r rune) {
-       // Test that the normal fallback handling after handleMethod for
-       // non-string verbs is used. This path should not be reached.
-       fmt.Fprintf(w, "Unreachable: %d", e)
-}
-
-func (e intError) FormatError(p errors.Printer) (next error) {
-       p.Printf("error %d", e)
-       return nil
-}
-
-// formatError is an error implementing Format instead of errors.Formatter.
-// The implementation mimics the implementation of github.com/pkg/errors.
-type formatError string
-
-func (e formatError) Error() string { return string(e) }
-
-func (e formatError) Format(s fmt.State, verb rune) {
-       // Body based on pkg/errors/errors.go
-       switch verb {
-       case 'v':
-               if s.Flag('+') {
-                       io.WriteString(s, string(e))
-                       fmt.Fprintf(s, ":\n%s", "otherfile.go:456")
-                       return
-               }
-               fallthrough
-       case 's':
-               io.WriteString(s, string(e))
-       case 'q':
-               fmt.Fprintf(s, "%q", string(e))
-       }
-}
-
-func (e formatError) GoString() string {
-       panic("should never be called")
-}
-
-type fmtTwiceErr struct {
-       format string
-       args   []interface{}
-}
-
-func fmtTwice(format string, a ...interface{}) error {
-       return fmtTwiceErr{format, a}
-}
-
-func (e fmtTwiceErr) Error() string { return fmt.Sprint(e) }
-
-func (e fmtTwiceErr) FormatError(p errors.Printer) (next error) {
-       p.Printf(e.format, e.args...)
-       p.Print("/")
-       p.Printf(e.format, e.args...)
-       return nil
-}
-
-func (e fmtTwiceErr) GoString() string {
-       return "2 times " + fmt.Sprintf(e.format, e.args...)
-}
-
-type panicValue struct{}
-
-func (panicValue) String() string { panic("panic") }
-
-var rePath = regexp.MustCompile(`( [^ ]*)fmt.*test\.`)
-var reLine = regexp.MustCompile(":[0-9]*\n?$")
-
-func cleanPath(s string) string {
-       s = rePath.ReplaceAllString(s, "/path.")
-       s = reLine.ReplaceAllString(s, ":xxx")
-       s = strings.Replace(s, "\n   ", "", -1)
-       s = strings.Replace(s, " /", "/", -1)
-       return s
-}
-
-func errToParts(err error) (a []string) {
-       for err != nil {
-               var p testPrinter
-               if errors.Unwrap(err) != nil {
-                       p.str += "wraps:"
-               }
-               f, ok := err.(errors.Formatter)
-               if !ok {
-                       a = append(a, err.Error())
-                       break
-               }
-               err = f.FormatError(&p)
-               a = append(a, cleanPath(p.str))
-       }
-       return a
-
-}
-
-type testPrinter struct {
-       str string
-}
-
-func (p *testPrinter) Print(a ...interface{}) {
-       p.str += fmt.Sprint(a...)
-}
-
-func (p *testPrinter) Printf(format string, a ...interface{}) {
-       p.str += fmt.Sprintf(format, a...)
-}
-
-func (p *testPrinter) Detail() bool {
-       p.str += " /"
-       return true
-}
index 0aa6670366b67b5096d8534b0a8470a139b7f969..74e600cab262011d35026edfe492fb2b39206556 100644 (file)
@@ -34,11 +34,6 @@ type fmtFlags struct {
        // different, flagless formats set at the top level.
        plusV  bool
        sharpV bool
-
-       // error-related flags.
-       inDetail    bool
-       needNewline bool
-       needColon   bool
 }
 
 // A fmt is the raw formatter used by Printf etc.
diff --git a/src/fmt/format_example_test.go b/src/fmt/format_example_test.go
deleted file mode 100644 (file)
index 386f10e..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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_test
-
-import (
-       "errors"
-       "fmt"
-       "path/filepath"
-       "regexp"
-)
-
-func baz() error { return errors.New("baz flopped") }
-func bar() error { return fmt.Errorf("bar(nameserver 139): %v", baz()) }
-func foo() error { return fmt.Errorf("foo: %s", bar()) }
-
-func Example_formatting() {
-       err := foo()
-       fmt.Println("Error:")
-       fmt.Printf("%v\n", err)
-       fmt.Println()
-       fmt.Println("Detailed error:")
-       fmt.Println(stripPath(fmt.Sprintf("%+v\n", err)))
-       // Output:
-       // Error:
-       // foo: bar(nameserver 139): baz flopped
-       //
-       // Detailed error:
-       // foo:
-       //     fmt_test.foo
-       //         fmt/format_example_test.go:16
-       //   - bar(nameserver 139):
-       //     fmt_test.bar
-       //         fmt/format_example_test.go:15
-       //   - baz flopped:
-       //     fmt_test.baz
-       //         fmt/format_example_test.go:14
-}
-
-func stripPath(s string) string {
-       rePath := regexp.MustCompile(`( [^ ]*)fmt`)
-       s = rePath.ReplaceAllString(s, " fmt")
-       s = filepath.ToSlash(s)
-       return s
-}
index 1fa424bfdea417014f6d7ec85fdcb44f5c3f8b40..e597639429189e6966ba96d2cbff009e191c8536 100644 (file)
@@ -217,6 +217,12 @@ func Sprintf(format string, a ...interface{}) string {
        return s
 }
 
+// Errorf formats according to a format specifier and returns the string
+// as a value that satisfies error.
+func Errorf(format string, a ...interface{}) error {
+       return errors.New(Sprintf(format, a...))
+}
+
 // These routines do not take a format string
 
 // Fprint formats using the default formats for its operands and writes to w.
@@ -570,22 +576,12 @@ func (p *pp) handleMethods(verb rune) (handled bool) {
        if p.erroring {
                return
        }
-       switch x := p.arg.(type) {
-       case errors.Formatter:
-               handled = true
-               defer p.catchPanic(p.arg, verb, "FormatError")
-               return fmtError(p, verb, x)
-
-       case Formatter:
+       // Is it a Formatter?
+       if formatter, ok := p.arg.(Formatter); ok {
                handled = true
                defer p.catchPanic(p.arg, verb, "Format")
-               x.Format(p, verb)
+               formatter.Format(p, verb)
                return
-
-       case error:
-               handled = true
-               defer p.catchPanic(p.arg, verb, "Error")
-               return fmtError(p, verb, x)
        }
 
        // If we're doing Go syntax and the argument knows how to supply it, take care of it now.
@@ -603,7 +599,18 @@ func (p *pp) handleMethods(verb rune) (handled bool) {
                // Println etc. set verb to %v, which is "stringable".
                switch verb {
                case 'v', 's', 'x', 'X', 'q':
-                       if v, ok := p.arg.(Stringer); ok {
+                       // Is it an error or Stringer?
+                       // The duplication in the bodies is necessary:
+                       // setting handled and deferring catchPanic
+                       // must happen before calling the method.
+                       switch v := p.arg.(type) {
+                       case error:
+                               handled = true
+                               defer p.catchPanic(p.arg, verb, "Error")
+                               p.fmtString(v.Error(), verb)
+                               return
+
+                       case Stringer:
                                handled = true
                                defer p.catchPanic(p.arg, verb, "String")
                                p.fmtString(v.String(), verb)
index c1010c1534ce71a3861a2998574ad8429a4e54fe..e4184c647803580f1fcb628863098ee19d1c4da6 100644 (file)
@@ -34,7 +34,7 @@ import (
 //
 var pkgDeps = map[string][]string{
        // L0 is the lowest level, core, nearly unavoidable packages.
-       "errors":                  {"runtime", "internal/errinternal", "internal/reflectlite"},
+       "errors":                  {"runtime", "internal/reflectlite"},
        "io":                      {"errors", "sync", "sync/atomic"},
        "runtime":                 {"unsafe", "runtime/internal/atomic", "runtime/internal/sys", "runtime/internal/math", "internal/cpu", "internal/bytealg"},
        "runtime/internal/sys":    {},
@@ -46,7 +46,6 @@ var pkgDeps = map[string][]string{
        "unsafe":                  {},
        "internal/cpu":            {},
        "internal/bytealg":        {"unsafe", "internal/cpu"},
-       "internal/errinternal":    {},
        "internal/reflectlite":    {"runtime", "unsafe"},
 
        "L0": {
@@ -186,7 +185,7 @@ var pkgDeps = map[string][]string{
        },
 
        // Formatted I/O: few dependencies (L1) but we must add reflect and internal/fmtsort.
-       "fmt": {"L1", "bytes", "strings", "os", "reflect", "internal/errinternal", "internal/fmtsort"},
+       "fmt": {"L1", "os", "reflect", "internal/fmtsort"},
        "log": {"L1", "os", "fmt", "time"},
 
        // Packages used by testing must be low-level (L2+fmt).
diff --git a/src/internal/errinternal/errinternal.go b/src/internal/errinternal/errinternal.go
deleted file mode 100644 (file)
index f484ac0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2019 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 errinternal
-
-// NewError creates a new error as created by errors.New, but with one
-// additional stack frame depth.
-var NewError func(msg string, err error) error
index 6d6a56a0c74719f63fe4ce192db9c9942bb63b17..50dd4678d4ab391be388cbc1893463284fdb6524 100644 (file)
@@ -34,7 +34,8 @@ func TestIsTimeout(t *testing.T) {
                {true, ttError{timeout: true}},
                {true, isError{os.ErrTimeout}},
                {true, os.ErrTimeout},
-               {true, fmt.Errorf("wrap: %w", os.ErrTimeout)},
+               // TODO: restore when %w is reimplemented
+               //{true, fmt.Errorf("wrap: %w", os.ErrTimeout)},
                {false, ttError{timeout: false}},
                {false, errors.New("error")},
        } {
@@ -52,7 +53,8 @@ func TestIsTemporary(t *testing.T) {
                {true, ttError{temporary: true}},
                {true, isError{os.ErrTemporary}},
                {true, os.ErrTemporary},
-               {true, fmt.Errorf("wrap: %w", os.ErrTemporary)},
+               // TODO: restore when %w is reimplemented
+               //{true, fmt.Errorf("wrap: %w", os.ErrTemporary)},
                {false, ttError{temporary: false}},
                {false, errors.New("error")},
        } {