Skip to content

Commit 7294ede

Browse files
lukechampinebradfitz
authored andcommitted
[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: 1b07f0c GitHub-Pull-Request: #30406 Reviewed-on: https://go-review.googlesource.com/c/163745 Reviewed-by: Rob Pike <[email protected]> Reviewed-by: Keith Randall <[email protected]> Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> (cherry picked from commit 9d40fad) Reviewed-on: https://go-review.googlesource.com/c/go/+/164617 Run-TryBot: Brad Fitzpatrick <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent f062f48 commit 7294ede

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

src/internal/fmtsort/sort.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ func compare(aVal, bVal reflect.Value) int {
167167
if c, ok := nilCompare(aVal, bVal); ok {
168168
return c
169169
}
170-
c := compare(reflect.ValueOf(aType), reflect.ValueOf(bType))
170+
c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type()))
171171
if c != 0 {
172172
return c
173173
}

src/internal/fmtsort/sort_test.go

+38-4
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,6 @@ var sortTests = []sortTest{
126126
map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"},
127127
"[3 4]:34 [7 1]:71 [7 2]:72",
128128
},
129-
{
130-
map[interface{}]string{7: "7", 4: "4", 3: "3", nil: "nil"},
131-
"<nil>:nil 3:3 4:4 7:7",
132-
},
133129
}
134130

135131
func sprint(data interface{}) string {
@@ -210,3 +206,41 @@ func TestOrder(t *testing.T) {
210206
}
211207
}
212208
}
209+
210+
func TestInterface(t *testing.T) {
211+
// A map containing multiple concrete types should be sorted by type,
212+
// then value. However, the relative ordering of types is unspecified,
213+
// so test this by checking the presence of sorted subgroups.
214+
m := map[interface{}]string{
215+
[2]int{1, 0}: "",
216+
[2]int{0, 1}: "",
217+
true: "",
218+
false: "",
219+
3.1: "",
220+
2.1: "",
221+
1.1: "",
222+
math.NaN(): "",
223+
3: "",
224+
2: "",
225+
1: "",
226+
"c": "",
227+
"b": "",
228+
"a": "",
229+
struct{ x, y int }{1, 0}: "",
230+
struct{ x, y int }{0, 1}: "",
231+
}
232+
got := sprint(m)
233+
typeGroups := []string{
234+
"NaN: 1.1: 2.1: 3.1:", // float64
235+
"false: true:", // bool
236+
"1: 2: 3:", // int
237+
"a: b: c:", // string
238+
"[0 1]: [1 0]:", // [2]int
239+
"{0 1}: {1 0}:", // struct{ x int; y int }
240+
}
241+
for _, g := range typeGroups {
242+
if !strings.Contains(got, g) {
243+
t.Errorf("sorted map should contain %q", g)
244+
}
245+
}
246+
}

0 commit comments

Comments
 (0)