Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1b07f0c

Browse files
committedFeb 28, 2019
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 the machine address of the value's type, then by the value itself. Sorting based on machine address results in unpredictable output, but will at least be deterministic across runs of the same program. Fixes golang#30398
1 parent b5a68a9 commit 1b07f0c

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)
Please sign in to comment.