Report with primitive types in diffs (#65)

When the formatted strings are identical, the reporter tries to fallback
on more exact formatting. This fallback should include the types for
primitive types since the difference can simply be between
an int and an uint.

Fixes #64
diff --git a/cmp/compare_test.go b/cmp/compare_test.go
index 5cff328..84c645b 100644
--- a/cmp/compare_test.go
+++ b/cmp/compare_test.go
@@ -453,6 +453,17 @@
 				return x == nil && y == nil
 			}, cmp.Ignore()),
 		},
+	}, {
+		label: label,
+		x:     []interface{}{map[string]interface{}{"avg": 0.278, "hr": 65, "name": "Mark McGwire"}, map[string]interface{}{"avg": 0.288, "hr": 63, "name": "Sammy Sosa"}},
+		y:     []interface{}{map[string]interface{}{"avg": 0.278, "hr": 65.0, "name": "Mark McGwire"}, map[string]interface{}{"avg": 0.288, "hr": 63.0, "name": "Sammy Sosa"}},
+		wantDiff: `
+root[0]["hr"]:
+	-: int(65)
+	+: float64(65)
+root[1]["hr"]:
+	-: int(63)
+	+: float64(63)`,
 	}}
 }
 
diff --git a/cmp/internal/value/format.go b/cmp/internal/value/format.go
index 6de45c5..657e508 100644
--- a/cmp/internal/value/format.go
+++ b/cmp/internal/value/format.go
@@ -22,24 +22,28 @@
 //	* Avoids printing struct fields that are zero
 //	* Prints a nil-slice as being nil, not empty
 //	* Prints map entries in deterministic order
-func Format(v reflect.Value, useStringer bool) string {
-	return formatAny(v, formatConfig{useStringer, true, true, true}, nil)
+func Format(v reflect.Value, conf FormatConfig) string {
+	conf.printType = true
+	conf.followPointers = true
+	conf.realPointers = true
+	return formatAny(v, conf, nil)
 }
 
-type formatConfig struct {
-	useStringer    bool // Should the String method be used if available?
-	printType      bool // Should we print the type before the value?
-	followPointers bool // Should we recursively follow pointers?
-	realPointers   bool // Should we print the real address of pointers?
+type FormatConfig struct {
+	UseStringer        bool // Should the String method be used if available?
+	printType          bool // Should we print the type before the value?
+	PrintPrimitiveType bool // Should we print the type of primitives?
+	followPointers     bool // Should we recursively follow pointers?
+	realPointers       bool // Should we print the real address of pointers?
 }
 
-func formatAny(v reflect.Value, conf formatConfig, visited map[uintptr]bool) string {
+func formatAny(v reflect.Value, conf FormatConfig, visited map[uintptr]bool) string {
 	// TODO: Should this be a multi-line printout in certain situations?
 
 	if !v.IsValid() {
 		return "<non-existent>"
 	}
-	if conf.useStringer && v.Type().Implements(stringerIface) && v.CanInterface() {
+	if conf.UseStringer && v.Type().Implements(stringerIface) && v.CanInterface() {
 		if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() {
 			return "<nil>"
 		}
@@ -150,7 +154,7 @@
 				continue // Elide zero value fields
 			}
 			name := v.Type().Field(i).Name
-			subConf.useStringer = conf.useStringer
+			subConf.UseStringer = conf.UseStringer
 			s := formatAny(vv, subConf, visited)
 			ss = append(ss, fmt.Sprintf("%s: %s", name, s))
 		}
@@ -183,14 +187,14 @@
 	return qs
 }
 
-func formatPrimitive(t reflect.Type, v interface{}, conf formatConfig) string {
-	if conf.printType && t.PkgPath() != "" {
+func formatPrimitive(t reflect.Type, v interface{}, conf FormatConfig) string {
+	if conf.printType && (conf.PrintPrimitiveType || t.PkgPath() != "") {
 		return fmt.Sprintf("%v(%v)", t, v)
 	}
 	return fmt.Sprintf("%v", v)
 }
 
-func formatPointer(v reflect.Value, conf formatConfig) string {
+func formatPointer(v reflect.Value, conf FormatConfig) string {
 	p := v.Pointer()
 	if !conf.realPointers {
 		p = 0 // For deterministic printing purposes
diff --git a/cmp/internal/value/format_test.go b/cmp/internal/value/format_test.go
index 36c4f23..45cc256 100644
--- a/cmp/internal/value/format_test.go
+++ b/cmp/internal/value/format_test.go
@@ -85,7 +85,7 @@
 		// ensure the format logic does not depend on read-write access
 		// to the reflect.Value.
 		v := reflect.ValueOf(struct{ x interface{} }{tt.in}).Field(0)
-		got := formatAny(v, formatConfig{useStringer: true, printType: true, followPointers: true}, nil)
+		got := formatAny(v, FormatConfig{UseStringer: true, printType: true, followPointers: true}, nil)
 		if got != tt.want {
 			t.Errorf("test %d, Format():\ngot  %q\nwant %q", i, got, tt.want)
 		}
diff --git a/cmp/reporter.go b/cmp/reporter.go
index 3be5664..20e9f18 100644
--- a/cmp/reporter.go
+++ b/cmp/reporter.go
@@ -30,12 +30,12 @@
 	const maxLines = 256
 	r.ndiffs++
 	if r.nbytes < maxBytes && r.nlines < maxLines {
-		sx := value.Format(x, true)
-		sy := value.Format(y, true)
+		sx := value.Format(x, value.FormatConfig{UseStringer: true})
+		sy := value.Format(y, value.FormatConfig{UseStringer: true})
 		if sx == sy {
-			// Stringer is not helpful, so rely on more exact formatting.
-			sx = value.Format(x, false)
-			sy = value.Format(y, false)
+			// Unhelpful output, so use more exact formatting.
+			sx = value.Format(x, value.FormatConfig{PrintPrimitiveType: true})
+			sy = value.Format(y, value.FormatConfig{PrintPrimitiveType: true})
 		}
 		s := fmt.Sprintf("%#v:\n\t-: %s\n\t+: %s\n", p, sx, sy)
 		r.diffs = append(r.diffs, s)