Destructure Wrap{,f} into WithStack(WithMessage(err, msg))

Introduces WithMessage as well as errors.fundamental, errors.withMessage
and errors.withStack internal types.

Adjust tests for the new wrapped format when combining fundamental and
wrapped errors.
diff --git a/errors.go b/errors.go
index d3d2234..915bbdb 100644
--- a/errors.go
+++ b/errors.go
@@ -87,24 +87,57 @@
 package errors
 
 import (
-	"errors"
 	"fmt"
 	"io"
 )
 
 // New returns an error with the supplied message.
+// New also records the stack trace at the point it was called.
 func New(message string) error {
-	err := errors.New(message)
-	return &withStack{
-		err,
-		callers(),
+	return &fundamental{
+		msg:   message,
+		stack: callers(),
 	}
 }
 
 // Errorf formats according to a format specifier and returns the string
 // as a value that satisfies error.
+// Errorf also records the stack trace at the point it was called.
 func Errorf(format string, args ...interface{}) error {
-	err := fmt.Errorf(format, args...)
+	return &fundamental{
+		msg:   fmt.Sprintf(format, args...),
+		stack: callers(),
+	}
+}
+
+// fundamental is an error that has a message and a stack, but no caller.
+type fundamental struct {
+	msg string
+	*stack
+}
+
+func (f *fundamental) Error() string { return f.msg }
+
+func (f *fundamental) Format(s fmt.State, verb rune) {
+	switch verb {
+	case 'v':
+		if s.Flag('+') {
+			io.WriteString(s, f.msg)
+			f.stack.Format(s, verb)
+			return
+		}
+		fallthrough
+	case 's', 'q':
+		io.WriteString(s, f.msg)
+	}
+}
+
+// WithStack annotates err with a stack trace at the point WithStack was called.
+// If err is nil, WithStack returns nil.
+func WithStack(err error) error {
+	if err == nil {
+		return nil
+	}
 	return &withStack{
 		err,
 		callers(),
@@ -116,47 +149,19 @@
 	*stack
 }
 
+func (w *withStack) Cause() error { return w.error }
+
 func (w *withStack) Format(s fmt.State, verb rune) {
 	switch verb {
 	case 'v':
 		if s.Flag('+') {
-			io.WriteString(s, w.Error())
+			fmt.Fprintf(s, "%+v", w.Cause())
 			w.stack.Format(s, verb)
 			return
 		}
 		fallthrough
 	case 's':
 		io.WriteString(s, w.Error())
-	}
-}
-
-type cause struct {
-	cause error
-	msg   string
-}
-
-func (c cause) Error() string { return fmt.Sprintf("%s: %v", c.msg, c.Cause()) }
-func (c cause) Cause() error  { return c.cause }
-
-// wrapper is an error implementation returned by Wrap and Wrapf
-// that implements its own fmt.Formatter.
-type wrapper struct {
-	cause
-	*stack
-}
-
-func (w wrapper) Format(s fmt.State, verb rune) {
-	switch verb {
-	case 'v':
-		if s.Flag('+') {
-			fmt.Fprintf(s, "%+v\n", w.Cause())
-			io.WriteString(s, w.msg)
-			fmt.Fprintf(s, "%+v", w.StackTrace())
-			return
-		}
-		fallthrough
-	case 's':
-		io.WriteString(s, w.Error())
 	case 'q':
 		fmt.Fprintf(s, "%q", w.Error())
 	}
@@ -164,31 +169,73 @@
 
 // Wrap returns an error annotating err with message.
 // If err is nil, Wrap returns nil.
+// Wrap is conceptually the same as calling
+//
+//     errors.WithStack(errors.WithMessage(err, msg))
 func Wrap(err error, message string) error {
 	if err == nil {
 		return nil
 	}
-	return wrapper{
-		cause: cause{
-			cause: err,
-			msg:   message,
-		},
-		stack: callers(),
+	err = &withMessage{
+		cause: err,
+		msg:   message,
+	}
+	return &withStack{
+		err,
+		callers(),
 	}
 }
 
 // Wrapf returns an error annotating err with the format specifier.
 // If err is nil, Wrapf returns nil.
+// Wrapf is conceptually the same as calling
+//
+//     errors.WithStack(errors.WithMessage(err, format, args...))
 func Wrapf(err error, format string, args ...interface{}) error {
 	if err == nil {
 		return nil
 	}
-	return wrapper{
-		cause: cause{
-			cause: err,
-			msg:   fmt.Sprintf(format, args...),
-		},
-		stack: callers(),
+	err = &withMessage{
+		cause: err,
+		msg:   fmt.Sprintf(format, args...),
+	}
+	return &withStack{
+		err,
+		callers(),
+	}
+}
+
+// WithMessage annotates err with a new message.
+// If err is nil, WithStack returns nil.
+func WithMessage(err error, message string) error {
+	if err == nil {
+		return nil
+	}
+	return &withMessage{
+		cause: err,
+		msg:   message,
+	}
+}
+
+type withMessage struct {
+	cause error
+	msg   string
+}
+
+func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
+func (w *withMessage) Cause() error  { return w.cause }
+
+func (w *withMessage) Format(s fmt.State, verb rune) {
+	switch verb {
+	case 'v':
+		if s.Flag('+') {
+			fmt.Fprintf(s, "%+v\n", w.Cause())
+			io.WriteString(s, w.msg)
+			return
+		}
+		fallthrough
+	case 's', 'q':
+		io.WriteString(s, w.Error())
 	}
 }
 
diff --git a/format_test.go b/format_test.go
index d1b2f1b..3b1746c 100644
--- a/format_test.go
+++ b/format_test.go
@@ -29,8 +29,8 @@
 			"\t.+/github.com/pkg/errors/format_test.go:25",
 	}}
 
-	for _, tt := range tests {
-		testFormatRegexp(t, tt.error, tt.format, tt.want)
+	for i, tt := range tests {
+		testFormatRegexp(t, i, tt.error, tt.format, tt.want)
 	}
 }
 
@@ -55,8 +55,8 @@
 			"\t.+/github.com/pkg/errors/format_test.go:51",
 	}}
 
-	for _, tt := range tests {
-		testFormatRegexp(t, tt.error, tt.format, tt.want)
+	for i, tt := range tests {
+		testFormatRegexp(t, i, tt.error, tt.format, tt.want)
 	}
 }
 
@@ -84,13 +84,31 @@
 		"%s",
 		"error: EOF",
 	}, {
+		Wrap(io.EOF, "error"),
+		"%v",
+		"error: EOF",
+	}, {
+		Wrap(io.EOF, "error"),
+		"%+v",
+		"EOF\n" +
+			"error\n" +
+			"github.com/pkg/errors.TestFormatWrap\n" +
+			"\t.+/github.com/pkg/errors/format_test.go:91",
+	}, {
+		Wrap(Wrap(io.EOF, "error1"), "error2"),
+		"%+v",
+		"EOF\n" +
+			"error1\n" +
+			"github.com/pkg/errors.TestFormatWrap\n" +
+			"\t.+/github.com/pkg/errors/format_test.go:98\n",
+	}, {
 		Wrap(New("error with space"), "context"),
 		"%q",
 		`"context: error with space"`,
 	}}
 
-	for _, tt := range tests {
-		testFormatRegexp(t, tt.error, tt.format, tt.want)
+	for i, tt := range tests {
+		testFormatRegexp(t, i, tt.error, tt.format, tt.want)
 	}
 }
 
@@ -100,21 +118,25 @@
 		format string
 		want   string
 	}{{
+		Wrapf(io.EOF, "error%d", 2),
+		"%s",
+		"error2: EOF",
+	}, {
+		Wrapf(io.EOF, "error%d", 2),
+		"%v",
+		"error2: EOF",
+	}, {
+		Wrapf(io.EOF, "error%d", 2),
+		"%+v",
+		"EOF\n" +
+			"error2\n" +
+			"github.com/pkg/errors.TestFormatWrapf\n" +
+			"\t.+/github.com/pkg/errors/format_test.go:129",
+	}, {
 		Wrapf(New("error"), "error%d", 2),
 		"%s",
 		"error2: error",
 	}, {
-		Wrap(io.EOF, "error"),
-		"%v",
-		"error: EOF",
-	}, {
-		Wrap(io.EOF, "error"),
-		"%+v",
-		"EOF\n" +
-			"error\n" +
-			"github.com/pkg/errors.TestFormatWrapf\n" +
-			"\t.+/github.com/pkg/errors/format_test.go:111",
-	}, {
 		Wrapf(New("error"), "error%d", 2),
 		"%v",
 		"error2: error",
@@ -123,22 +145,15 @@
 		"%+v",
 		"error\n" +
 			"github.com/pkg/errors.TestFormatWrapf\n" +
-			"\t.+/github.com/pkg/errors/format_test.go:122",
-	}, {
-		Wrap(Wrap(io.EOF, "error1"), "error2"),
-		"%+v",
-		"EOF\n" +
-			"error1\n" +
-			"github.com/pkg/errors.TestFormatWrapf\n" +
-			"\t.+/github.com/pkg/errors/format_test.go:128\n",
+			"\t.+/github.com/pkg/errors/format_test.go:144",
 	}}
 
-	for _, tt := range tests {
-		testFormatRegexp(t, tt.error, tt.format, tt.want)
+	for i, tt := range tests {
+		testFormatRegexp(t, i, tt.error, tt.format, tt.want)
 	}
 }
 
-func testFormatRegexp(t *testing.T, arg interface{}, format, want string) {
+func testFormatRegexp(t *testing.T, n int, arg interface{}, format, want string) {
 	got := fmt.Sprintf(format, arg)
 	lines := strings.SplitN(got, "\n", -1)
 	for i, w := range strings.SplitN(want, "\n", -1) {
@@ -147,7 +162,7 @@
 			t.Fatal(err)
 		}
 		if !match {
-			t.Errorf("fmt.Sprintf(%q, err): got: %q, want: %q", format, got, want)
+			t.Errorf("test %d: line %d: fmt.Sprintf(%q, err): got: %q, want: %q", n+1, i+1, format, got, want)
 		}
 	}
 }
diff --git a/stack_test.go b/stack_test.go
index da53daf..2624e45 100644
--- a/stack_test.go
+++ b/stack_test.go
@@ -120,8 +120,8 @@
 		"unknown:0",
 	}}
 
-	for _, tt := range tests {
-		testFormatRegexp(t, tt.Frame, tt.format, tt.want)
+	for i, tt := range tests {
+		testFormatRegexp(t, i, tt.Frame, tt.format, tt.want)
 	}
 }
 
@@ -204,7 +204,7 @@
 				"\t.+/github.com/pkg/errors/stack_test.go:198", // this is the stack of Errorf's caller's caller
 		},
 	}}
-	for _, tt := range tests {
+	for i, tt := range tests {
 		x, ok := tt.err.(interface {
 			StackTrace() StackTrace
 		})
@@ -214,7 +214,7 @@
 		}
 		st := x.StackTrace()
 		for j, want := range tt.want {
-			testFormatRegexp(t, st[j], "%+v", want)
+			testFormatRegexp(t, i, st[j], "%+v", want)
 		}
 	}
 }
@@ -286,7 +286,7 @@
 		`\[\]errors.Frame{stack_test.go:225, stack_test.go:284}`,
 	}}
 
-	for _, tt := range tests {
-		testFormatRegexp(t, tt.StackTrace, tt.format, tt.want)
+	for i, tt := range tests {
+		testFormatRegexp(t, i, tt.StackTrace, tt.format, tt.want)
 	}
 }