This applies only for cases where %w is not used.
The purpose of this change is to reduce test failures where tests
depend on these two being the same type, as they previously were.
Change-Id: I2dd28b93fe1d59f3cfbb4eb0875d1fb8ee699746
Reviewed-on: https://go-review.googlesource.com/c/go/+/167402
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
// Package errors implements functions to manipulate errors.
package errors
-import "runtime"
+import (
+ "internal/errinternal"
+ "runtime"
+)
// New returns an error that formats as the given text.
//
// Inline call to errors.Callers to improve performance.
var s Frame
runtime.Callers(2, s.frames[:])
- return &errorString{text, s}
+ 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}
+ }
}
// errorString is a trivial implementation of error.
type errorString struct {
s string
+ err error
frame Frame
}
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 nil
+ return e.err
}
import (
"errors"
+ "internal/errinternal"
"strings"
)
func Errorf(format string, a ...interface{}) error {
err, wrap := lastError(format, a)
if err == nil {
- return &noWrapError{Sprintf(format, a...), nil, errors.Caller(1)}
+ return errinternal.NewError(Sprintf(format, a...), nil)
}
// TODO: this is not entirely correct. The error value could be
if wrap {
return &wrapError{msg, err, errors.Caller(1)}
}
- return &noWrapError{msg, err, errors.Caller(1)}
+ return errinternal.NewError(msg, err)
}
func lastError(format string, a []interface{}) (err error, wrap bool) {
}
}
+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 {
//
var pkgDeps = map[string][]string{
// L0 is the lowest level, core, nearly unavoidable packages.
- "errors": {"runtime", "internal/reflectlite"},
+ "errors": {"runtime", "internal/errinternal", "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": {},
"unsafe": {},
"internal/cpu": {},
"internal/bytealg": {"unsafe", "internal/cpu"},
+ "internal/errinternal": {},
"internal/reflectlite": {"runtime", "unsafe"},
"L0": {
},
// Formatted I/O: few dependencies (L1) but we must add reflect and internal/fmtsort.
- "fmt": {"L1", "bytes", "strings", "os", "reflect", "internal/fmtsort"},
+ "fmt": {"L1", "bytes", "strings", "os", "reflect", "internal/errinternal", "internal/fmtsort"},
"log": {"L1", "os", "fmt", "time"},
// Packages used by testing must be low-level (L2+fmt).
--- /dev/null
+// 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