Merge tag v0.5.9 am: 380e26f982 am: 8bddf39794 am: 33ef859425

Original change: https://android-review.googlesource.com/c/platform/external/go-cmp/+/2320808

Change-Id: I14b6ad6891b5023adcbb19c4f53bab9b8dd9eea3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 5664da6..b49573d 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,14 +2,9 @@
 name: Test
 jobs:
   test:
-    env:
-      GOPATH: ${{ github.workspace }}
-    defaults:
-      run:
-        working-directory: ${{ env.GOPATH }}/src/github.com/${{ github.repository }}
     strategy:
       matrix:
-        go-version: [1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x, 1.16.x, 1.17.x]
+        go-version: [1.13.x, 1.14.x, 1.15.x, 1.16.x, 1.17.x, 1.18.x, 1.19.x]
         os: [ubuntu-latest, macos-latest]
     runs-on: ${{ matrix.os }}
     steps:
@@ -19,12 +14,8 @@
         go-version: ${{ matrix.go-version }}
     - name: Checkout code
       uses: actions/checkout@v2
-      with:
-        path: ${{ env.GOPATH }}/src/github.com/${{ github.repository }}
-    - name: Checkout dependencies
-      run: go get golang.org/x/xerrors
     - name: Test
       run: go test -v -race ./...
     - name: Format
-      if: matrix.go-version == '1.17.x'
+      if: matrix.go-version == '1.19.x'
       run: diff -u <(echo -n) <(gofmt -d .)
diff --git a/Android.gen.bp b/Android.gen.bp
index 0f9c559..e639079 100644
--- a/Android.gen.bp
+++ b/Android.gen.bp
@@ -1,5 +1,5 @@
 // Automatically generated with:
-// go2bp -rewrite github.com/google/go-cmp/cmp=go-cmp -exclude-src cmp/cmpopts/util_test.go -exclude-dep golang.org/x/xerrors
+// go2bp -rewrite github.com/google/go-cmp/cmp=go-cmp
 
 bootstrap_go_package {
     name: "go-cmp",
@@ -38,12 +38,14 @@
     ],
     srcs: [
         "cmp/cmpopts/equate.go",
-        "cmp/cmpopts/errors_go113.go",
         "cmp/cmpopts/ignore.go",
         "cmp/cmpopts/sort.go",
         "cmp/cmpopts/struct_filter.go",
         "cmp/cmpopts/xform.go",
     ],
+    testSrcs: [
+        "cmp/cmpopts/util_test.go",
+    ],
 }
 
 bootstrap_go_package {
@@ -126,10 +128,8 @@
         "cmp/internal/value/name.go",
         "cmp/internal/value/pointer_unsafe.go",
         "cmp/internal/value/sort.go",
-        "cmp/internal/value/zero.go",
     ],
     testSrcs: [
         "cmp/internal/value/name_test.go",
-        "cmp/internal/value/zero_test.go",
     ],
 }
diff --git a/METADATA b/METADATA
index 5615722..e34104a 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@
     type: GIT
     value: "https://github.com/google/go-cmp.git"
   }
-  version: "v0.5.7"
+  version: "v0.5.9"
   license_type: NOTICE
   last_upgrade_date {
     year: 2022
-    month: 3
-    day: 29
+    month: 11
+    day: 30
   }
 }
diff --git a/cmp/cmpopts/equate.go b/cmp/cmpopts/equate.go
index 62837c9..e54a76c 100644
--- a/cmp/cmpopts/equate.go
+++ b/cmp/cmpopts/equate.go
@@ -6,6 +6,7 @@
 package cmpopts
 
 import (
+	"errors"
 	"math"
 	"reflect"
 	"time"
@@ -41,6 +42,7 @@
 // The fraction and margin must be non-negative.
 //
 // The mathematical expression used is equivalent to:
+//
 //	|x-y| ≤ max(fraction*min(|x|, |y|), margin)
 //
 // EquateApprox can be used in conjunction with EquateNaNs.
@@ -146,3 +148,9 @@
 	_, ok2 := y.(error)
 	return ok1 && ok2
 }
+
+func compareErrors(x, y interface{}) bool {
+	xe := x.(error)
+	ye := y.(error)
+	return errors.Is(xe, ye) || errors.Is(ye, xe)
+}
diff --git a/cmp/cmpopts/errors_go113.go b/cmp/cmpopts/errors_go113.go
deleted file mode 100644
index 8eb2b84..0000000
--- a/cmp/cmpopts/errors_go113.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2021, 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.
-
-//go:build go1.13
-// +build go1.13
-
-package cmpopts
-
-import "errors"
-
-func compareErrors(x, y interface{}) bool {
-	xe := x.(error)
-	ye := y.(error)
-	return errors.Is(xe, ye) || errors.Is(ye, xe)
-}
diff --git a/cmp/cmpopts/errors_xerrors.go b/cmp/cmpopts/errors_xerrors.go
deleted file mode 100644
index 60b0727..0000000
--- a/cmp/cmpopts/errors_xerrors.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2021, 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.
-
-//go:build !go1.13
-// +build !go1.13
-
-// TODO(≥go1.13): For support on <go1.13, we use the xerrors package.
-// Drop this file when we no longer support older Go versions.
-
-package cmpopts
-
-import "golang.org/x/xerrors"
-
-func compareErrors(x, y interface{}) bool {
-	xe := x.(error)
-	ye := y.(error)
-	return xerrors.Is(xe, ye) || xerrors.Is(ye, xe)
-}
diff --git a/cmp/cmpopts/example_test.go b/cmp/cmpopts/example_test.go
index 0cf2513..4b9a8ab 100644
--- a/cmp/cmpopts/example_test.go
+++ b/cmp/cmpopts/example_test.go
@@ -39,7 +39,7 @@
 	//   	SSID:      "CoffeeShopWiFi",
 	// - 	IPAddress: s"192.168.0.2",
 	// + 	IPAddress: s"192.168.0.1",
-	//   	NetMask:   {0xff, 0xff, 0x00, 0x00},
+	//   	NetMask:   s"ffff0000",
 	//   	Clients: []cmpopts_test.Client{
 	//   		... // 3 identical elements
 	//   		{Hostname: "espresso", ...},
diff --git a/cmp/cmpopts/sort.go b/cmp/cmpopts/sort.go
index a646d74..0eb2a75 100644
--- a/cmp/cmpopts/sort.go
+++ b/cmp/cmpopts/sort.go
@@ -18,9 +18,9 @@
 // sort any slice with element type V that is assignable to T.
 //
 // The less function must be:
-//	• Deterministic: less(x, y) == less(x, y)
-//	• Irreflexive: !less(x, x)
-//	• Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
+//   - Deterministic: less(x, y) == less(x, y)
+//   - Irreflexive: !less(x, x)
+//   - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
 //
 // The less function does not have to be "total". That is, if !less(x, y) and
 // !less(y, x) for two elements x and y, their relative order is maintained.
@@ -91,10 +91,10 @@
 // use Comparers on K or the K.Equal method if it exists.
 //
 // The less function must be:
-//	• Deterministic: less(x, y) == less(x, y)
-//	• Irreflexive: !less(x, x)
-//	• Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
-//	• Total: if x != y, then either less(x, y) or less(y, x)
+//   - Deterministic: less(x, y) == less(x, y)
+//   - Irreflexive: !less(x, x)
+//   - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
+//   - Total: if x != y, then either less(x, y) or less(y, x)
 //
 // SortMaps can be used in conjunction with EquateEmpty.
 func SortMaps(lessFunc interface{}) cmp.Option {
diff --git a/cmp/cmpopts/struct_filter.go b/cmp/cmpopts/struct_filter.go
index a09829c..ca11a40 100644
--- a/cmp/cmpopts/struct_filter.go
+++ b/cmp/cmpopts/struct_filter.go
@@ -67,12 +67,14 @@
 // fieldTree represents a set of dot-separated identifiers.
 //
 // For example, inserting the following selectors:
+//
 //	Foo
 //	Foo.Bar.Baz
 //	Foo.Buzz
 //	Nuka.Cola.Quantum
 //
 // Results in a tree of the form:
+//
 //	{sub: {
 //		"Foo": {ok: true, sub: {
 //			"Bar": {sub: {
diff --git a/cmp/cmpopts/util_test.go b/cmp/cmpopts/util_test.go
index b19bcab..7adeb9b 100644
--- a/cmp/cmpopts/util_test.go
+++ b/cmp/cmpopts/util_test.go
@@ -17,7 +17,6 @@
 	"time"
 
 	"github.com/google/go-cmp/cmp"
-	"golang.org/x/xerrors"
 )
 
 type (
@@ -531,14 +530,14 @@
 		reason:    "user-defined EOF is not exactly equal",
 	}, {
 		label:     "EquateErrors",
-		x:         xerrors.Errorf("wrapped: %w", io.EOF),
+		x:         fmt.Errorf("wrapped: %w", io.EOF),
 		y:         io.EOF,
 		opts:      []cmp.Option{EquateErrors()},
 		wantEqual: true,
 		reason:    "wrapped io.EOF is equal according to errors.Is",
 	}, {
 		label:     "EquateErrors",
-		x:         xerrors.Errorf("wrapped: %w", io.EOF),
+		x:         fmt.Errorf("wrapped: %w", io.EOF),
 		y:         io.EOF,
 		wantEqual: false,
 		reason:    "wrapped io.EOF is not equal without EquateErrors option",
@@ -585,14 +584,14 @@
 		reason:    "user-defined EOF is not exactly equal",
 	}, {
 		label:     "EquateErrors",
-		x:         xerrors.Errorf("wrapped: %w", io.EOF),
+		x:         fmt.Errorf("wrapped: %w", io.EOF),
 		y:         io.EOF,
 		opts:      []cmp.Option{EquateErrors()},
 		wantEqual: true,
 		reason:    "wrapped io.EOF is equal according to errors.Is",
 	}, {
 		label:     "EquateErrors",
-		x:         xerrors.Errorf("wrapped: %w", io.EOF),
+		x:         fmt.Errorf("wrapped: %w", io.EOF),
 		y:         io.EOF,
 		wantEqual: false,
 		reason:    "wrapped io.EOF is not equal without EquateErrors option",
@@ -639,14 +638,14 @@
 		reason:    "user-defined EOF is not exactly equal",
 	}, {
 		label:     "EquateErrors",
-		x:         struct{ E error }{xerrors.Errorf("wrapped: %w", io.EOF)},
+		x:         struct{ E error }{fmt.Errorf("wrapped: %w", io.EOF)},
 		y:         struct{ E error }{io.EOF},
 		opts:      []cmp.Option{EquateErrors()},
 		wantEqual: true,
 		reason:    "wrapped io.EOF is equal according to errors.Is",
 	}, {
 		label:     "EquateErrors",
-		x:         struct{ E error }{xerrors.Errorf("wrapped: %w", io.EOF)},
+		x:         struct{ E error }{fmt.Errorf("wrapped: %w", io.EOF)},
 		y:         struct{ E error }{io.EOF},
 		wantEqual: false,
 		reason:    "wrapped io.EOF is not equal without EquateErrors option",
@@ -1073,7 +1072,7 @@
 	}, {
 		label: "AcyclicTransformer",
 		x:     "this is a sentence",
-		y: "this   			is a 			sentence",
+		y:     "this   			is a 			sentence",
 		opts: []cmp.Option{
 			AcyclicTransformer("", strings.Fields),
 		},
diff --git a/cmp/cmpopts/xform.go b/cmp/cmpopts/xform.go
index 4eb49d6..8812443 100644
--- a/cmp/cmpopts/xform.go
+++ b/cmp/cmpopts/xform.go
@@ -23,6 +23,7 @@
 // that the transformer cannot be recursively applied upon its own output.
 //
 // An example use case is a transformer that splits a string by lines:
+//
 //	AcyclicTransformer("SplitLines", func(s string) []string{
 //		return strings.Split(s, "\n")
 //	})
diff --git a/cmp/compare.go b/cmp/compare.go
index 2a54467..087320d 100644
--- a/cmp/compare.go
+++ b/cmp/compare.go
@@ -13,21 +13,21 @@
 //
 // The primary features of cmp are:
 //
-// • When the default behavior of equality does not suit the needs of the test,
-// custom equality functions can override the equality operation.
-// For example, an equality function may report floats as equal so long as they
-// are within some tolerance of each other.
+//   - When the default behavior of equality does not suit the test's needs,
+//     custom equality functions can override the equality operation.
+//     For example, an equality function may report floats as equal so long as
+//     they are within some tolerance of each other.
 //
-// • Types that have an Equal method may use that method to determine equality.
-// This allows package authors to determine the equality operation for the types
-// that they define.
+//   - Types with an Equal method may use that method to determine equality.
+//     This allows package authors to determine the equality operation
+//     for the types that they define.
 //
-// • If no custom equality functions are used and no Equal method is defined,
-// equality is determined by recursively comparing the primitive kinds on both
-// values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported
-// fields are not compared by default; they result in panics unless suppressed
-// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly
-// compared using the Exporter option.
+//   - If no custom equality functions are used and no Equal method is defined,
+//     equality is determined by recursively comparing the primitive kinds on
+//     both values, much like reflect.DeepEqual. Unlike reflect.DeepEqual,
+//     unexported fields are not compared by default; they result in panics
+//     unless suppressed by using an Ignore option (see cmpopts.IgnoreUnexported)
+//     or explicitly compared using the Exporter option.
 package cmp
 
 import (
@@ -40,28 +40,30 @@
 	"github.com/google/go-cmp/cmp/internal/value"
 )
 
+// TODO(≥go1.18): Use any instead of interface{}.
+
 // Equal reports whether x and y are equal by recursively applying the
 // following rules in the given order to x and y and all of their sub-values:
 //
-// • Let S be the set of all Ignore, Transformer, and Comparer options that
-// remain after applying all path filters, value filters, and type filters.
-// If at least one Ignore exists in S, then the comparison is ignored.
-// If the number of Transformer and Comparer options in S is greater than one,
-// then Equal panics because it is ambiguous which option to use.
-// If S contains a single Transformer, then use that to transform the current
-// values and recursively call Equal on the output values.
-// If S contains a single Comparer, then use that to compare the current values.
-// Otherwise, evaluation proceeds to the next rule.
+//   - Let S be the set of all Ignore, Transformer, and Comparer options that
+//     remain after applying all path filters, value filters, and type filters.
+//     If at least one Ignore exists in S, then the comparison is ignored.
+//     If the number of Transformer and Comparer options in S is non-zero,
+//     then Equal panics because it is ambiguous which option to use.
+//     If S contains a single Transformer, then use that to transform
+//     the current values and recursively call Equal on the output values.
+//     If S contains a single Comparer, then use that to compare the current values.
+//     Otherwise, evaluation proceeds to the next rule.
 //
-// • If the values have an Equal method of the form "(T) Equal(T) bool" or
-// "(T) Equal(I) bool" where T is assignable to I, then use the result of
-// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and
-// evaluation proceeds to the next rule.
+//   - If the values have an Equal method of the form "(T) Equal(T) bool" or
+//     "(T) Equal(I) bool" where T is assignable to I, then use the result of
+//     x.Equal(y) even if x or y is nil. Otherwise, no such method exists and
+//     evaluation proceeds to the next rule.
 //
-// • Lastly, try to compare x and y based on their basic kinds.
-// Simple kinds like booleans, integers, floats, complex numbers, strings, and
-// channels are compared using the equivalent of the == operator in Go.
-// Functions are only equal if they are both nil, otherwise they are unequal.
+//   - Lastly, try to compare x and y based on their basic kinds.
+//     Simple kinds like booleans, integers, floats, complex numbers, strings,
+//     and channels are compared using the equivalent of the == operator in Go.
+//     Functions are only equal if they are both nil, otherwise they are unequal.
 //
 // Structs are equal if recursively calling Equal on all fields report equal.
 // If a struct contains unexported fields, Equal panics unless an Ignore option
@@ -142,7 +144,7 @@
 	// so that they have the same parent type.
 	var t reflect.Type
 	if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() {
-		t = reflect.TypeOf((*interface{})(nil)).Elem()
+		t = anyType
 		if vx.IsValid() {
 			vvx := reflect.New(t).Elem()
 			vvx.Set(vx)
@@ -637,7 +639,9 @@
 // Next increments the state and reports whether a check should be performed.
 //
 // Checks occur every Nth function call, where N is a triangular number:
+//
 //	0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ...
+//
 // See https://en.wikipedia.org/wiki/Triangular_number
 //
 // This sequence ensures that the cost of checks drops significantly as
diff --git a/cmp/compare_test.go b/cmp/compare_test.go
index 9ad9456..88b7d45 100644
--- a/cmp/compare_test.go
+++ b/cmp/compare_test.go
@@ -43,7 +43,7 @@
 const goldenHeaderPrefix = "<<< "
 const goldenFooterPrefix = ">>> "
 
-/// mustParseGolden parses a file as a set of key-value pairs.
+// mustParseGolden parses a file as a set of key-value pairs.
 //
 // The syntax is simple and looks something like:
 //
@@ -104,6 +104,7 @@
 
 var now = time.Date(2009, time.November, 10, 23, 00, 00, 00, time.UTC)
 
+// TODO(≥go1.18): Define a generic function that boxes a value on the heap.
 func newInt(n int) *int { return &n }
 
 type Stringer string
@@ -885,6 +886,7 @@
 			FloatsB []MyFloat
 			FloatsC MyFloats
 		}
+		PointerString *string
 	)
 
 	return []test{{
@@ -1351,6 +1353,73 @@
 	"bar": true,
 }`,
 		reason: "short multiline JSON should prefer triple-quoted string diff as it is more readable",
+	}, {
+		label: label + "/PointerToStringOrAny",
+		x: func() *string {
+			var v string = "hello"
+			return &v
+		}(),
+		y: func() *interface{} {
+			var v interface{} = "hello"
+			return &v
+		}(),
+		reason: "mismatched types between any and *any should print differently",
+	}, {
+		label: label + "/NamedPointer",
+		x: func() *string {
+			v := "hello"
+			return &v
+		}(),
+		y: func() PointerString {
+			v := "hello"
+			return &v
+		}(),
+		reason: "mismatched pointer types should print differently",
+	}, {
+		label:  label + "/MapStringAny",
+		x:      map[string]interface{}{"key": int(0)},
+		y:      map[string]interface{}{"key": uint(0)},
+		reason: "mismatched underlying value within interface",
+	}, {
+		label:  label + "/StructFieldAny",
+		x:      struct{ X interface{} }{int(0)},
+		y:      struct{ X interface{} }{uint(0)},
+		reason: "mismatched underlying value within interface",
+	}, {
+		label: label + "/SliceOfBytesText",
+		x: [][]byte{
+			[]byte("hello"), []byte("foo"), []byte("barbaz"), []byte("blahdieblah"),
+		},
+		y: [][]byte{
+			[]byte("foo"), []byte("foo"), []byte("barbaz"), []byte("added"), []byte("here"), []byte("hrmph"),
+		},
+		reason: "should print text byte slices as strings",
+	}, {
+		label: label + "/SliceOfBytesBinary",
+		x: [][]byte{
+			[]byte("\xde\xad\xbe\xef"), []byte("\xffoo"), []byte("barbaz"), []byte("blahdieblah"),
+		},
+		y: [][]byte{
+			[]byte("\xffoo"), []byte("foo"), []byte("barbaz"), []byte("added"), []byte("here"), []byte("hrmph\xff"),
+		},
+		reason: "should print text byte slices as strings except those with binary",
+	}, {
+		label: label + "/ManyEscapeCharacters",
+		x: `[
+	{"Base32": "NA======"},
+	{"Base32": "NBSQ===="},
+	{"Base32": "NBSWY==="},
+	{"Base32": "NBSWY3A="},
+	{"Base32": "NBSWY3DP"}
+]`,
+		y: `[
+	{"Base32": "NB======"},
+	{"Base32": "NBSQ===="},
+	{"Base32": "NBSWY==="},
+	{"Base32": "NBSWY3A="},
+	{"Base32": "NBSWY3DP"}
+]`,
+		reason: "should use line-based diffing since byte-based diffing is unreadable due to heavy amounts of escaping",
 	}}
 }
 
diff --git a/cmp/example_test.go b/cmp/example_test.go
index e1f4338..9968149 100644
--- a/cmp/example_test.go
+++ b/cmp/example_test.go
@@ -37,7 +37,7 @@
 	//   	SSID:      "CoffeeShopWiFi",
 	// - 	IPAddress: s"192.168.0.2",
 	// + 	IPAddress: s"192.168.0.1",
-	//   	NetMask:   {0xff, 0xff, 0x00, 0x00},
+	//   	NetMask:   s"ffff0000",
 	//   	Clients: []cmp_test.Client{
 	//   		... // 2 identical elements
 	//   		{Hostname: "macchiato", IPAddress: s"192.168.0.153", LastSeen: s"2009-11-10 23:39:43 +0000 UTC"},
diff --git a/cmp/internal/diff/diff.go b/cmp/internal/diff/diff.go
index bc196b1..a248e54 100644
--- a/cmp/internal/diff/diff.go
+++ b/cmp/internal/diff/diff.go
@@ -127,9 +127,9 @@
 // This function returns an edit-script, which is a sequence of operations
 // needed to convert one list into the other. The following invariants for
 // the edit-script are maintained:
-//	• eq == (es.Dist()==0)
-//	• nx == es.LenX()
-//	• ny == es.LenY()
+//   - eq == (es.Dist()==0)
+//   - nx == es.LenX()
+//   - ny == es.LenY()
 //
 // This algorithm is not guaranteed to be an optimal solution (i.e., one that
 // produces an edit-script with a minimal Levenshtein distance). This algorithm
@@ -169,12 +169,13 @@
 	// A diagonal edge is equivalent to a matching symbol between both X and Y.
 
 	// Invariants:
-	//	• 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx
-	//	• 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny
+	//   - 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx
+	//   - 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny
 	//
 	// In general:
-	//	• fwdFrontier.X < revFrontier.X
-	//	• fwdFrontier.Y < revFrontier.Y
+	//   - fwdFrontier.X < revFrontier.X
+	//   - fwdFrontier.Y < revFrontier.Y
+	//
 	// Unless, it is time for the algorithm to terminate.
 	fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)}
 	revPath := path{-1, point{nx, ny}, make(EditScript, 0)}
@@ -195,19 +196,21 @@
 	// computing sub-optimal edit-scripts between two lists.
 	//
 	// The algorithm is approximately as follows:
-	//	• Searching for differences switches back-and-forth between
-	//	a search that starts at the beginning (the top-left corner), and
-	//	a search that starts at the end (the bottom-right corner). The goal of
-	//	the search is connect with the search from the opposite corner.
-	//	• As we search, we build a path in a greedy manner, where the first
-	//	match seen is added to the path (this is sub-optimal, but provides a
-	//	decent result in practice). When matches are found, we try the next pair
-	//	of symbols in the lists and follow all matches as far as possible.
-	//	• When searching for matches, we search along a diagonal going through
-	//	through the "frontier" point. If no matches are found, we advance the
-	//	frontier towards the opposite corner.
-	//	• This algorithm terminates when either the X coordinates or the
-	//	Y coordinates of the forward and reverse frontier points ever intersect.
+	//   - Searching for differences switches back-and-forth between
+	//     a search that starts at the beginning (the top-left corner), and
+	//     a search that starts at the end (the bottom-right corner).
+	//     The goal of the search is connect with the search
+	//     from the opposite corner.
+	//   - As we search, we build a path in a greedy manner,
+	//     where the first match seen is added to the path (this is sub-optimal,
+	//     but provides a decent result in practice). When matches are found,
+	//     we try the next pair of symbols in the lists and follow all matches
+	//     as far as possible.
+	//   - When searching for matches, we search along a diagonal going through
+	//     through the "frontier" point. If no matches are found,
+	//     we advance the frontier towards the opposite corner.
+	//   - This algorithm terminates when either the X coordinates or the
+	//     Y coordinates of the forward and reverse frontier points ever intersect.
 
 	// This algorithm is correct even if searching only in the forward direction
 	// or in the reverse direction. We do both because it is commonly observed
@@ -389,6 +392,7 @@
 func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy }
 
 // zigzag maps a consecutive sequence of integers to a zig-zag sequence.
+//
 //	[0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...]
 func zigzag(x int) int {
 	if x&1 != 0 {
diff --git a/cmp/internal/value/zero.go b/cmp/internal/value/zero.go
deleted file mode 100644
index 9147a29..0000000
--- a/cmp/internal/value/zero.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2017, 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 value
-
-import (
-	"math"
-	"reflect"
-)
-
-// IsZero reports whether v is the zero value.
-// This does not rely on Interface and so can be used on unexported fields.
-func IsZero(v reflect.Value) bool {
-	switch v.Kind() {
-	case reflect.Bool:
-		return v.Bool() == false
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return v.Int() == 0
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return v.Uint() == 0
-	case reflect.Float32, reflect.Float64:
-		return math.Float64bits(v.Float()) == 0
-	case reflect.Complex64, reflect.Complex128:
-		return math.Float64bits(real(v.Complex())) == 0 && math.Float64bits(imag(v.Complex())) == 0
-	case reflect.String:
-		return v.String() == ""
-	case reflect.UnsafePointer:
-		return v.Pointer() == 0
-	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
-		return v.IsNil()
-	case reflect.Array:
-		for i := 0; i < v.Len(); i++ {
-			if !IsZero(v.Index(i)) {
-				return false
-			}
-		}
-		return true
-	case reflect.Struct:
-		for i := 0; i < v.NumField(); i++ {
-			if !IsZero(v.Field(i)) {
-				return false
-			}
-		}
-		return true
-	}
-	return false
-}
diff --git a/cmp/internal/value/zero_test.go b/cmp/internal/value/zero_test.go
deleted file mode 100644
index ddaa337..0000000
--- a/cmp/internal/value/zero_test.go
+++ /dev/null
@@ -1,52 +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 value
-
-import (
-	"archive/tar"
-	"math"
-	"reflect"
-	"testing"
-)
-
-func TestIsZero(t *testing.T) {
-	tests := []struct {
-		in   interface{}
-		want bool
-	}{
-		{0, true},
-		{1, false},
-		{"", true},
-		{"foo", false},
-		{[]byte(nil), true},
-		{[]byte{}, false},
-		{map[string]bool(nil), true},
-		{map[string]bool{}, false},
-		{tar.Header{}, true},
-		{&tar.Header{}, false},
-		{tar.Header{Name: "foo"}, false},
-		{(chan bool)(nil), true},
-		{make(chan bool), false},
-		{(func(*testing.T))(nil), true},
-		{TestIsZero, false},
-		{[...]int{0, 0, 0}, true},
-		{[...]int{0, 1, 0}, false},
-		{math.Copysign(0, +1), true},
-		{math.Copysign(0, -1), false},
-		{complex(math.Copysign(0, +1), math.Copysign(0, +1)), true},
-		{complex(math.Copysign(0, -1), math.Copysign(0, +1)), false},
-		{complex(math.Copysign(0, +1), math.Copysign(0, -1)), false},
-		{complex(math.Copysign(0, -1), math.Copysign(0, -1)), false},
-	}
-
-	for _, tt := range tests {
-		t.Run("", func(t *testing.T) {
-			got := IsZero(reflect.ValueOf(tt.in))
-			if got != tt.want {
-				t.Errorf("IsZero(%v) = %v, want %v", tt.in, got, tt.want)
-			}
-		})
-	}
-}
diff --git a/cmp/options.go b/cmp/options.go
index e57b9eb..1f9ca9c 100644
--- a/cmp/options.go
+++ b/cmp/options.go
@@ -33,6 +33,7 @@
 }
 
 // applicableOption represents the following types:
+//
 //	Fundamental: ignore | validator | *comparer | *transformer
 //	Grouping:    Options
 type applicableOption interface {
@@ -43,6 +44,7 @@
 }
 
 // coreOption represents the following types:
+//
 //	Fundamental: ignore | validator | *comparer | *transformer
 //	Filters:     *pathFilter | *valuesFilter
 type coreOption interface {
@@ -336,9 +338,9 @@
 // both implement T.
 //
 // The equality function must be:
-//	• Symmetric: equal(x, y) == equal(y, x)
-//	• Deterministic: equal(x, y) == equal(x, y)
-//	• Pure: equal(x, y) does not modify x or y
+//   - Symmetric: equal(x, y) == equal(y, x)
+//   - Deterministic: equal(x, y) == equal(x, y)
+//   - Pure: equal(x, y) does not modify x or y
 func Comparer(f interface{}) Option {
 	v := reflect.ValueOf(f)
 	if !function.IsType(v.Type(), function.Equal) || v.IsNil() {
@@ -430,7 +432,7 @@
 }
 
 // Result represents the comparison result for a single node and
-// is provided by cmp when calling Result (see Reporter).
+// is provided by cmp when calling Report (see Reporter).
 type Result struct {
 	_     [0]func() // Make Result incomparable
 	flags resultFlags
diff --git a/cmp/path.go b/cmp/path.go
index c710034..a0a5885 100644
--- a/cmp/path.go
+++ b/cmp/path.go
@@ -41,13 +41,13 @@
 	// The type of each valid value is guaranteed to be identical to Type.
 	//
 	// In some cases, one or both may be invalid or have restrictions:
-	//	• For StructField, both are not interface-able if the current field
-	//	is unexported and the struct type is not explicitly permitted by
-	//	an Exporter to traverse unexported fields.
-	//	• For SliceIndex, one may be invalid if an element is missing from
-	//	either the x or y slice.
-	//	• For MapIndex, one may be invalid if an entry is missing from
-	//	either the x or y map.
+	//   - For StructField, both are not interface-able if the current field
+	//     is unexported and the struct type is not explicitly permitted by
+	//     an Exporter to traverse unexported fields.
+	//   - For SliceIndex, one may be invalid if an element is missing from
+	//     either the x or y slice.
+	//   - For MapIndex, one may be invalid if an entry is missing from
+	//     either the x or y map.
 	//
 	// The provided values must not be mutated.
 	Values() (vx, vy reflect.Value)
@@ -94,6 +94,7 @@
 // The simplified path only contains struct field accesses.
 //
 // For example:
+//
 //	MyMap.MySlices.MyField
 func (pa Path) String() string {
 	var ss []string
@@ -108,6 +109,7 @@
 // GoString returns the path to a specific node using Go syntax.
 //
 // For example:
+//
 //	(*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField
 func (pa Path) GoString() string {
 	var ssPre, ssPost []string
@@ -159,7 +161,7 @@
 	if ps.typ == nil {
 		return "<nil>"
 	}
-	s := ps.typ.String()
+	s := value.TypeString(ps.typ, false)
 	if s == "" || strings.ContainsAny(s, "{}\n") {
 		return "root" // Type too simple or complex to print
 	}
@@ -282,7 +284,7 @@
 
 func (ta TypeAssertion) Type() reflect.Type             { return ta.typ }
 func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy }
-func (ta TypeAssertion) String() string                 { return fmt.Sprintf(".(%v)", ta.typ) }
+func (ta TypeAssertion) String() string                 { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) }
 
 // Transform is a transformation from the parent type to the current type.
 type Transform struct{ *transform }
diff --git a/cmp/report_compare.go b/cmp/report_compare.go
index 104bb30..2050bf6 100644
--- a/cmp/report_compare.go
+++ b/cmp/report_compare.go
@@ -7,8 +7,6 @@
 import (
 	"fmt"
 	"reflect"
-
-	"github.com/google/go-cmp/cmp/internal/value"
 )
 
 // numContextRecords is the number of surrounding equal records to print.
@@ -116,7 +114,10 @@
 	}
 
 	// For leaf nodes, format the value based on the reflect.Values alone.
-	if v.MaxDepth == 0 {
+	// As a special case, treat equal []byte as a leaf nodes.
+	isBytes := v.Type.Kind() == reflect.Slice && v.Type.Elem() == byteType
+	isEqualBytes := isBytes && v.NumDiff+v.NumIgnored+v.NumTransformed == 0
+	if v.MaxDepth == 0 || isEqualBytes {
 		switch opts.DiffMode {
 		case diffUnknown, diffIdentical:
 			// Format Equal.
@@ -245,11 +246,11 @@
 				var isZero bool
 				switch opts.DiffMode {
 				case diffIdentical:
-					isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueY)
+					isZero = r.Value.ValueX.IsZero() || r.Value.ValueY.IsZero()
 				case diffRemoved:
-					isZero = value.IsZero(r.Value.ValueX)
+					isZero = r.Value.ValueX.IsZero()
 				case diffInserted:
-					isZero = value.IsZero(r.Value.ValueY)
+					isZero = r.Value.ValueY.IsZero()
 				}
 				if isZero {
 					continue
diff --git a/cmp/report_reflect.go b/cmp/report_reflect.go
index 76c04fd..2ab41fa 100644
--- a/cmp/report_reflect.go
+++ b/cmp/report_reflect.go
@@ -16,6 +16,13 @@
 	"github.com/google/go-cmp/cmp/internal/value"
 )
 
+var (
+	anyType    = reflect.TypeOf((*interface{})(nil)).Elem()
+	stringType = reflect.TypeOf((*string)(nil)).Elem()
+	bytesType  = reflect.TypeOf((*[]byte)(nil)).Elem()
+	byteType   = reflect.TypeOf((*byte)(nil)).Elem()
+)
+
 type formatValueOptions struct {
 	// AvoidStringer controls whether to avoid calling custom stringer
 	// methods like error.Error or fmt.Stringer.String.
@@ -184,7 +191,7 @@
 		}
 		for i := 0; i < v.NumField(); i++ {
 			vv := v.Field(i)
-			if value.IsZero(vv) {
+			if vv.IsZero() {
 				continue // Elide fields with zero values
 			}
 			if len(list) == maxLen {
@@ -205,13 +212,13 @@
 		}
 
 		// Check whether this is a []byte of text data.
-		if t.Elem() == reflect.TypeOf(byte(0)) {
+		if t.Elem() == byteType {
 			b := v.Bytes()
 			isPrintSpace := func(r rune) bool { return unicode.IsPrint(r) || unicode.IsSpace(r) }
 			if len(b) > 0 && utf8.Valid(b) && len(bytes.TrimFunc(b, isPrintSpace)) == 0 {
 				out = opts.formatString("", string(b))
 				skipType = true
-				return opts.WithTypeMode(emitType).FormatType(t, out)
+				return opts.FormatType(t, out)
 			}
 		}
 
@@ -282,7 +289,12 @@
 		}
 		defer ptrs.Pop()
 
-		skipType = true // Let the underlying value print the type instead
+		// Skip the name only if this is an unnamed pointer type.
+		// Otherwise taking the address of a value does not reproduce
+		// the named pointer type.
+		if v.Type().Name() == "" {
+			skipType = true // Let the underlying value print the type instead
+		}
 		out = opts.FormatValue(v.Elem(), t.Kind(), ptrs)
 		out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out)
 		out = &textWrap{Prefix: "&", Value: out}
@@ -293,7 +305,6 @@
 		}
 		// Interfaces accept different concrete types,
 		// so configure the underlying value to explicitly print the type.
-		skipType = true // Print the concrete type instead
 		return opts.WithTypeMode(emitType).FormatValue(v.Elem(), t.Kind(), ptrs)
 	default:
 		panic(fmt.Sprintf("%v kind not handled", v.Kind()))
diff --git a/cmp/report_slices.go b/cmp/report_slices.go
index 68b5c1a..23e444f 100644
--- a/cmp/report_slices.go
+++ b/cmp/report_slices.go
@@ -104,7 +104,7 @@
 	case t.Kind() == reflect.String:
 		sx, sy = vx.String(), vy.String()
 		isString = true
-	case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)):
+	case t.Kind() == reflect.Slice && t.Elem() == byteType:
 		sx, sy = string(vx.Bytes()), string(vy.Bytes())
 		isString = true
 	case t.Kind() == reflect.Array:
@@ -147,7 +147,10 @@
 			})
 			efficiencyLines := float64(esLines.Dist()) / float64(len(esLines))
 			efficiencyBytes := float64(esBytes.Dist()) / float64(len(esBytes))
-			isPureLinedText = efficiencyLines < 4*efficiencyBytes
+			quotedLength := len(strconv.Quote(sx + sy))
+			unquotedLength := len(sx) + len(sy)
+			escapeExpansionRatio := float64(quotedLength) / float64(unquotedLength)
+			isPureLinedText = efficiencyLines < 4*efficiencyBytes || escapeExpansionRatio > 1.1
 		}
 	}
 
@@ -171,12 +174,13 @@
 		// differences in a string literal. This format is more readable,
 		// but has edge-cases where differences are visually indistinguishable.
 		// This format is avoided under the following conditions:
-		//	• A line starts with `"""`
-		//	• A line starts with "..."
-		//	• A line contains non-printable characters
-		//	• Adjacent different lines differ only by whitespace
+		//   - A line starts with `"""`
+		//   - A line starts with "..."
+		//   - A line contains non-printable characters
+		//   - Adjacent different lines differ only by whitespace
 		//
 		// For example:
+		//
 		//		"""
 		//		... // 3 identical lines
 		//		foo
@@ -231,7 +235,7 @@
 			var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"}
 			switch t.Kind() {
 			case reflect.String:
-				if t != reflect.TypeOf(string("")) {
+				if t != stringType {
 					out = opts.FormatType(t, out)
 				}
 			case reflect.Slice:
@@ -326,12 +330,12 @@
 	switch t.Kind() {
 	case reflect.String:
 		out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
-		if t != reflect.TypeOf(string("")) {
+		if t != stringType {
 			out = opts.FormatType(t, out)
 		}
 	case reflect.Slice:
 		out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
-		if t != reflect.TypeOf([]byte(nil)) {
+		if t != bytesType {
 			out = opts.FormatType(t, out)
 		}
 	}
@@ -446,7 +450,6 @@
 //		{NumIdentical: 3},
 //		{NumInserted: 1},
 //	]
-//
 func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) {
 	var prevMode byte
 	lastStats := func(mode byte) *diffStats {
@@ -503,7 +506,6 @@
 //		{NumIdentical: 8, NumRemoved: 12, NumInserted: 3},
 //		{NumIdentical: 63},
 //	]
-//
 func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats {
 	groups, groupsOrig := groups[:0], groups
 	for i, ds := range groupsOrig {
@@ -548,7 +550,6 @@
 //		{NumRemoved: 9},
 //		{NumIdentical: 64}, // incremented by 10
 //	]
-//
 func cleanupSurroundingIdentical(groups []diffStats, eq func(i, j int) bool) []diffStats {
 	var ix, iy int // indexes into sequence x and y
 	for i, ds := range groups {
diff --git a/cmp/report_text.go b/cmp/report_text.go
index 0fd46d7..388fcf5 100644
--- a/cmp/report_text.go
+++ b/cmp/report_text.go
@@ -393,6 +393,7 @@
 // String prints a humanly-readable summary of coalesced records.
 //
 // Example:
+//
 //	diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields"
 func (s diffStats) String() string {
 	var ss []string
diff --git a/cmp/testdata/diffs b/cmp/testdata/diffs
index d207803..be77b95 100644
--- a/cmp/testdata/diffs
+++ b/cmp/testdata/diffs
@@ -241,9 +241,9 @@
   		"string",
   	}),
   	Bytes: []uint8(Inverse(SplitBytes, [][]uint8{
-  		{0x73, 0x6f, 0x6d, 0x65},
-  		{0x6d, 0x75, 0x6c, 0x74, ...},
-  		{0x6c, 0x69, 0x6e, 0x65},
+  		"some",
+  		"multi",
+  		"line",
   		{
 - 			0x62,
 + 			0x42,
@@ -1134,6 +1134,66 @@
   	"""
   )
 >>> TestDiff/Reporter/ShortJSON
+<<< TestDiff/Reporter/PointerToStringOrAny
+  any(
+- 	&string("hello"),
++ 	&any(string("hello")),
+  )
+>>> TestDiff/Reporter/PointerToStringOrAny
+<<< TestDiff/Reporter/NamedPointer
+  any(
+- 	&string("hello"),
++ 	cmp_test.PointerString(&string("hello")),
+  )
+>>> TestDiff/Reporter/NamedPointer
+<<< TestDiff/Reporter/MapStringAny
+  map[string]any{
+- 	"key": int(0),
++ 	"key": uint(0),
+  }
+>>> TestDiff/Reporter/MapStringAny
+<<< TestDiff/Reporter/StructFieldAny
+  struct{ X any }{
+- 	X: int(0),
++ 	X: uint(0),
+  }
+>>> TestDiff/Reporter/StructFieldAny
+<<< TestDiff/Reporter/SliceOfBytesText
+  [][]uint8{
+- 	"hello",
+  	"foo",
++ 	"foo",
+  	"barbaz",
++ 	"added",
++ 	"here",
+- 	"blahdieblah",
++ 	"hrmph",
+  }
+>>> TestDiff/Reporter/SliceOfBytesText
+<<< TestDiff/Reporter/SliceOfBytesBinary
+  [][]uint8{
+- 	{0xde, 0xad, 0xbe, 0xef},
+  	{0xff, 0x6f, 0x6f},
++ 	"foo",
+  	"barbaz",
++ 	"added",
++ 	"here",
+- 	"blahdieblah",
++ 	{0x68, 0x72, 0x6d, 0x70, 0x68, 0xff},
+  }
+>>> TestDiff/Reporter/SliceOfBytesBinary
+<<< TestDiff/Reporter/ManyEscapeCharacters
+  (
+  	"""
+  	[
+- 		{"Base32": "NA======"},
++ 		{"Base32": "NB======"},
+  		{"Base32": "NBSQ===="},
+  		{"Base32": "NBSWY==="},
+  	... // 3 identical lines
+  	"""
+  )
+>>> TestDiff/Reporter/ManyEscapeCharacters
 <<< TestDiff/EmbeddedStruct/ParentStructA/Inequal
   teststructs.ParentStructA{
   	privateStruct: teststructs.privateStruct{
diff --git a/go.mod b/go.mod
index 4cdb762..f55cea6 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,3 @@
 module github.com/google/go-cmp
 
-go 1.11
-
-require golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
+go 1.13
diff --git a/go.sum b/go.sum
deleted file mode 100644
index 3ab73ea..0000000
--- a/go.sum
+++ /dev/null
@@ -1,2 +0,0 @@
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=