Refactor errors.location to be a stack of callers (#25)
Refactory errors.location to be a stack of callers rather than the
topmost caller. This is in perparation for storing the entire error
stack inside topmost error.
diff --git a/errors.go b/errors.go
index 254c6dd..af74fc3 100644
--- a/errors.go
+++ b/errors.go
@@ -55,12 +55,11 @@
"strings"
)
-// location represents a program counter that
-// implements the Location() method.
-type location uintptr
+// location represents a stack of programm counters.
+type location []uintptr
func (l location) Location() (string, int) {
- pc := uintptr(l) - 1
+ pc := l[0] - 1
fn := runtime.FuncForPC(pc)
if fn == nil {
return "unknown", 0
@@ -110,13 +109,12 @@
// New returns an error that formats as the given text.
func New(text string) error {
- pc, _, _, _ := runtime.Caller(1)
return struct {
error
location
}{
errors.New(text),
- location(pc),
+ caller(),
}
}
@@ -132,13 +130,12 @@
// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
func Errorf(format string, args ...interface{}) error {
- pc, _, _, _ := runtime.Caller(1)
return struct {
error
location
}{
fmt.Errorf(format, args...),
- location(pc),
+ caller(),
}
}
@@ -148,8 +145,7 @@
if cause == nil {
return nil
}
- pc, _, _, _ := runtime.Caller(1)
- return wrap(cause, message, pc)
+ return wrap(cause, message, caller())
}
// Wrapf returns an error annotating the cause with the format specifier.
@@ -158,11 +154,10 @@
if cause == nil {
return nil
}
- pc, _, _, _ := runtime.Caller(1)
- return wrap(cause, fmt.Sprintf(format, args...), pc)
+ return wrap(cause, fmt.Sprintf(format, args...), caller())
}
-func wrap(err error, msg string, pc uintptr) error {
+func wrap(err error, msg string, loc location) error {
return struct {
cause
location
@@ -171,7 +166,7 @@
cause: err,
message: msg,
},
- location(pc),
+ loc,
}
}
@@ -239,3 +234,9 @@
err = cause.Cause()
}
}
+
+func caller() location {
+ var pcs [1]uintptr
+ n := runtime.Callers(3, pcs[:])
+ return location(pcs[0:n])
+}