errors/fmt: add adaptor support

Embedded error in Formatter interface to allow
assigning an errors.Formatter to an error variable without a cast.

Change-Id: I6fff75b6128256877c31fa6d7e1cdcaeabfbdeeb
Reviewed-on: https://go-review.googlesource.com/c/152999
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/errors/errors.go b/errors/errors.go
index d7ab482..39d7c5e 100644
--- a/errors/errors.go
+++ b/errors/errors.go
@@ -28,7 +28,7 @@
 	return e.s
 }
 
-func (e *errorString) Format(p Printer) (next error) {
+func (e *errorString) FormatError(p Printer) (next error) {
 	p.Print(e.s)
 	e.frame.Format(p)
 	return nil
diff --git a/errors/fmt/adaptor.go b/errors/fmt/adaptor.go
new file mode 100644
index 0000000..2da6a9d
--- /dev/null
+++ b/errors/fmt/adaptor.go
@@ -0,0 +1,31 @@
+// 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 "golang.org/x/exp/errors"
+
+// The functionality in this file is to provide adaptors only. It will not
+// be included in the standard library.
+
+// FormatError calls the FormatError method of err with a errors.Printer
+// configured according to s and verb and writes the result to s.
+func FormatError(s State, verb rune, err errors.Formatter) {
+	// Assuming this function is only called from the Format method, and given
+	// that FormatError takes precedence over Format, it cannot be called from
+	// any package that supports errors.Formatter. It is therefore safe to
+	// disregard that State may be a specific printer implementation and use one
+	// of our choice instead.
+	p := newPrinter()
+	if verb == 'v' {
+		if s.Flag('#') {
+			p.fmt.sharpV = true
+		}
+		if s.Flag('+') {
+			p.fmt.plusV = true
+		}
+	}
+	fmtError(p, verb, err)
+	s.Write(p.buf)
+}
diff --git a/errors/fmt/errors.go b/errors/fmt/errors.go
index 3150cc5..06fcffe 100644
--- a/errors/fmt/errors.go
+++ b/errors/fmt/errors.go
@@ -74,7 +74,7 @@
 	return Sprint(e)
 }
 
-func (e *noWrapError) Format(p errors.Printer) (next error) {
+func (e *noWrapError) FormatError(p errors.Printer) (next error) {
 	p.Print(e.msg)
 	e.frame.Format(p)
 	return e.err
@@ -90,7 +90,7 @@
 	return Sprint(e)
 }
 
-func (e *wrapError) Format(p errors.Printer) (next error) {
+func (e *wrapError) FormatError(p errors.Printer) (next error) {
 	p.Print(e.msg)
 	e.frame.Format(p)
 	return e.err
@@ -148,16 +148,8 @@
 		w.fmt.inDetail = false
 		switch v := err.(type) {
 		case errors.Formatter:
-			err = v.Format((*errPP)(w))
-		// TODO: This case is for supporting old error implementations.
-		// It may eventually disappear.
-		case interface{ FormatError(errors.Printer) error }:
 			err = v.FormatError((*errPP)(w))
 		case Formatter:
-			// Discard verb, but keep the flags. Discarding the verb prevents
-			// nested quoting and other unwanted behavior. Preserving flags
-			// recursively signals a request for detail, if interpreted as %+v.
-			w.fmt.fmtFlags = p.fmt.fmtFlags
 			if w.fmt.plusV {
 				v.Format((*errPPState)(w), 'v') // indent new lines
 			} else {
diff --git a/errors/fmt/errors_test.go b/errors/fmt/errors_test.go
index 6a0ce27..9feff95 100644
--- a/errors/fmt/errors_test.go
+++ b/errors/fmt/errors_test.go
@@ -88,9 +88,8 @@
 			"can't adumbrate elephant",
 			detailed{},
 		}
-		transition = &wrapped2{"elephant still on strike", detailed{}}
-		nonascii   = &wrapped{"café", nil}
-		newline    = &wrapped{"msg with\nnewline",
+		nonascii = &wrapped{"café", nil}
+		newline  = &wrapped{"msg with\nnewline",
 			&wrapped{"and another\none", nil}}
 		fallback  = &wrapped{"fallback", os.ErrNotExist}
 		oldAndNew = &wrapped{"new style", formatError("old style")}
@@ -133,15 +132,6 @@
 			"\n    and the 12 monkeys" +
 			"\n    are laughing",
 	}, {
-		err: transition,
-		fmt: "%+v",
-		want: "elephant still on strike:" +
-			"\n    somefile.go:123" +
-			"\n  - out of peanuts:" +
-			"\n    the elephant is on strike" +
-			"\n    and the 12 monkeys" +
-			"\n    are laughing",
-	}, {
 		err:  simple,
 		fmt:  "%#v",
 		want: "&fmt_test.wrapped{msg:\"simple\", err:error(nil)}",
@@ -150,7 +140,7 @@
 		fmt: "%+v",
 		want: "something:" +
 			"\n    golang.org/x/exp/errors/fmt_test.TestErrorFormatter" +
-			"\n        .+/golang.org/x/exp/errors/fmt/errors_test.go:98" +
+			"\n        .+/golang.org/x/exp/errors/fmt/errors_test.go:97" +
 			"\n    something more",
 		regexp: true,
 	}, {
@@ -311,21 +301,7 @@
 
 func (e wrapped) Error() string { return "should call Format" }
 
-func (e wrapped) Format(p errors.Printer) (next error) {
-	p.Print(e.msg)
-	p.Detail()
-	p.Print("somefile.go:123")
-	return e.err
-}
-
-type wrapped2 struct {
-	msg string
-	err error
-}
-
-func (e wrapped2) Error() string { return "should call Format" }
-
-func (e wrapped2) FormatError(p errors.Printer) (next error) {
+func (e wrapped) FormatError(p errors.Printer) (next error) {
 	p.Print(e.msg)
 	p.Detail()
 	p.Print("somefile.go:123")
@@ -338,7 +314,7 @@
 
 func (e detailed) Error() string { return fmt.Sprint(e) }
 
-func (detailed) Format(p errors.Printer) (next error) {
+func (detailed) FormatError(p errors.Printer) (next error) {
 	p.Printf("out of %s", "peanuts")
 	p.Detail()
 	p.Print("the elephant is on strike\n")
@@ -352,7 +328,7 @@
 
 func (e *withFrameAndMore) Error() string { return fmt.Sprint(e) }
 
-func (e *withFrameAndMore) Format(p errors.Printer) (next error) {
+func (e *withFrameAndMore) FormatError(p errors.Printer) (next error) {
 	p.Print("something")
 	if p.Detail() {
 		e.frame.Format(p)
@@ -365,7 +341,7 @@
 
 func (e spurious) Error() string { return fmt.Sprint(e) }
 
-func (e spurious) Format(p errors.Printer) (next error) {
+func (e spurious) FormatError(p errors.Printer) (next error) {
 	p.Print("spurious")
 	p.Detail() // Call detail even if we don't print anything
 	if e == "" {
@@ -415,7 +391,7 @@
 
 func (e fmtTwiceErr) Error() string { return fmt.Sprint(e) }
 
-func (e fmtTwiceErr) Format(p errors.Printer) (next error) {
+func (e fmtTwiceErr) FormatError(p errors.Printer) (next error) {
 	p.Printf(e.format, e.args...)
 	p.Print("/")
 	p.Printf(e.format, e.args...)
@@ -452,7 +428,7 @@
 			a = append(a, err.Error())
 			break
 		}
-		err = f.Format(&p)
+		err = f.FormatError(&p)
 		a = append(a, cleanPath(p.str))
 	}
 	return a
diff --git a/errors/fmt/print.go b/errors/fmt/print.go
index 0374b0f..da3baf8 100644
--- a/errors/fmt/print.go
+++ b/errors/fmt/print.go
@@ -5,6 +5,7 @@
 package fmt
 
 import (
+	gofmt "fmt"
 	"io"
 	"os"
 	"reflect"
@@ -31,44 +32,31 @@
 	invReflectString  = "<invalid reflect.Value>"
 )
 
+// These interface need to be aliases so that implementations can be used
+// for different implementations.
+
 // State represents the printer state passed to custom formatters.
 // It provides access to the io.Writer interface plus information about
 // the flags and options for the operand's format specifier.
-type State interface {
-	// Write is the function to call to emit formatted output to be printed.
-	Write(b []byte) (n int, err error)
-	// Width returns the value of the width option and whether it has been set.
-	Width() (wid int, ok bool)
-	// Precision returns the value of the precision option and whether it has been set.
-	Precision() (prec int, ok bool)
-
-	// Flag reports whether the flag c, a character, has been set.
-	Flag(c int) bool
-}
+type State = gofmt.State
 
 // Formatter is the interface implemented by values with a custom formatter.
 // The implementation of Format may call Sprint(f) or Fprint(f) etc.
 // to generate its output.
-type Formatter interface {
-	Format(f State, c rune)
-}
+type Formatter = gofmt.Formatter
 
 // Stringer is implemented by any value that has a String method,
 // which defines the ``native'' format for that value.
 // The String method is used to print values passed as an operand
 // to any format that accepts a string or to an unformatted printer
 // such as Print.
-type Stringer interface {
-	String() string
-}
+type Stringer = gofmt.Stringer
 
 // GoStringer is implemented by any value that has a GoString method,
 // which defines the Go syntax for that value.
 // The GoString method is used to print values passed as an operand
 // to a %#v format.
-type GoStringer interface {
-	GoString() string
-}
+type GoStringer = gofmt.GoStringer
 
 // Use simple []byte instead of bytes.Buffer to avoid large dependency.
 type buffer []byte
@@ -556,17 +544,17 @@
 	if p.erroring {
 		return
 	}
-	// Is it a Formatter?
-	if formatter, ok := p.arg.(Formatter); ok {
+	switch x := p.arg.(type) {
+	case Formatter:
 		handled = true
 		defer p.catchPanic(p.arg, verb)
-		formatter.Format(p, verb)
+		x.Format(p, verb)
 		return
-	}
-	if err, ok := p.arg.(error); ok {
+
+	case error:
 		handled = true
 		defer p.catchPanic(p.arg, verb)
-		return fmtError(p, verb, err)
+		return fmtError(p, verb, x)
 	}
 
 	// If we're doing Go syntax and the argument knows how to supply it, take care of it now.
diff --git a/errors/format.go b/errors/format.go
index aed5de3..12deed3 100644
--- a/errors/format.go
+++ b/errors/format.go
@@ -6,9 +6,11 @@
 
 // A Formatter formats error messages.
 type Formatter interface {
-	// Format prints the receiver's first error and returns the next error in
+	error
+
+	// FormatError prints the receiver's first error and returns the next error in
 	// the error chain, if any.
-	Format(p Printer) (next error)
+	FormatError(p Printer) (next error)
 }
 
 // A Printer formats error messages.
diff --git a/errors/wrap.go b/errors/wrap.go
index 00d1cb2..c936d97 100644
--- a/errors/wrap.go
+++ b/errors/wrap.go
@@ -25,9 +25,9 @@
 	error
 }
 
-func (e noWrapper) Format(p Printer) (next error) {
+func (e noWrapper) FormatError(p Printer) (next error) {
 	if f, ok := e.error.(Formatter); ok {
-		return f.Format(p)
+		return f.FormatError(p)
 	}
 	p.Print(e.error)
 	return nil
diff --git a/errors/wrap_test.go b/errors/wrap_test.go
index c4d6fc6..f72425d 100644
--- a/errors/wrap_test.go
+++ b/errors/wrap_test.go
@@ -189,7 +189,7 @@
 
 func (errorD) Error() string { return "errorD" }
 
-func (errorD) Format(p errors.Printer) error {
+func (errorD) FormatError(p errors.Printer) error {
 	p.Print("errorD")
 	p.Detail()
 	p.Print("detail")