Commit 7294ede9 authored by lukechampine's avatar lukechampine Committed by Brad Fitzpatrick

[release-branch.go1.12] fmtsort: sort interfaces deterministically

Previously, the result of sorting a map[interface{}] containing
multiple concrete types was non-deterministic. To ensure consistent
results, sort first by type name, then by concrete value.

Fixes #30484

Change-Id: I10fd4b6a74eefbc87136853af6b2e689bc76ae9d
GitHub-Last-Rev: 1b07f0c275716e1b2834f74f9c67f897bae82882
GitHub-Pull-Request: golang/go#30406
Reviewed-on: https://go-review.googlesource.com/c/163745Reviewed-by: default avatarRob Pike <r@golang.org>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
(cherry picked from commit 9d40fadb)
Reviewed-on: https://go-review.googlesource.com/c/go/+/164617
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent f062f48c
...@@ -167,7 +167,7 @@ func compare(aVal, bVal reflect.Value) int { ...@@ -167,7 +167,7 @@ func compare(aVal, bVal reflect.Value) int {
if c, ok := nilCompare(aVal, bVal); ok { if c, ok := nilCompare(aVal, bVal); ok {
return c return c
} }
c := compare(reflect.ValueOf(aType), reflect.ValueOf(bType)) c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type()))
if c != 0 { if c != 0 {
return c return c
} }
......
...@@ -126,10 +126,6 @@ var sortTests = []sortTest{ ...@@ -126,10 +126,6 @@ var sortTests = []sortTest{
map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"}, map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"},
"[3 4]:34 [7 1]:71 [7 2]:72", "[3 4]:34 [7 1]:71 [7 2]:72",
}, },
{
map[interface{}]string{7: "7", 4: "4", 3: "3", nil: "nil"},
"<nil>:nil 3:3 4:4 7:7",
},
} }
func sprint(data interface{}) string { func sprint(data interface{}) string {
...@@ -210,3 +206,41 @@ func TestOrder(t *testing.T) { ...@@ -210,3 +206,41 @@ func TestOrder(t *testing.T) {
} }
} }
} }
func TestInterface(t *testing.T) {
// A map containing multiple concrete types should be sorted by type,
// then value. However, the relative ordering of types is unspecified,
// so test this by checking the presence of sorted subgroups.
m := map[interface{}]string{
[2]int{1, 0}: "",
[2]int{0, 1}: "",
true: "",
false: "",
3.1: "",
2.1: "",
1.1: "",
math.NaN(): "",
3: "",
2: "",
1: "",
"c": "",
"b": "",
"a": "",
struct{ x, y int }{1, 0}: "",
struct{ x, y int }{0, 1}: "",
}
got := sprint(m)
typeGroups := []string{
"NaN: 1.1: 2.1: 3.1:", // float64
"false: true:", // bool
"1: 2: 3:", // int
"a: b: c:", // string
"[0 1]: [1 0]:", // [2]int
"{0 1}: {1 0}:", // struct{ x int; y int }
}
for _, g := range typeGroups {
if !strings.Contains(got, g) {
t.Errorf("sorted map should contain %q", g)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment