]> Cypherpunks repositories - gostls13.git/commitdiff
fmtsort: sort interfaces deterministically
authorlukechampine <luke.champine@gmail.com>
Thu, 28 Feb 2019 19:03:18 +0000 (19:03 +0000)
committerKeith Randall <khr@golang.org>
Thu, 28 Feb 2019 21:09:49 +0000 (21:09 +0000)
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 #30398

Change-Id: I10fd4b6a74eefbc87136853af6b2e689bc76ae9d
GitHub-Last-Rev: 1b07f0c275716e1b2834f74f9c67f897bae82882
GitHub-Pull-Request: golang/go#30406
Reviewed-on: https://go-review.googlesource.com/c/163745
Reviewed-by: Rob Pike <r@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/internal/fmtsort/sort.go
src/internal/fmtsort/sort_test.go

index c959cbee1f8af7fa9f365e0587cceacdca9dfe82..70a305a3a10330674e285fe34c54d5a084c5d305 100644 (file)
@@ -167,7 +167,7 @@ func compare(aVal, bVal reflect.Value) int {
                if c, ok := nilCompare(aVal, bVal); ok {
                        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 {
                        return c
                }
index 6b10c775b0e93f87ff1c3537048cbae03d502824..e060d4bf5157aa4b81d5c2b27dae01dfe5c1581b 100644 (file)
@@ -126,10 +126,6 @@ var sortTests = []sortTest{
                map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"},
                "[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 {
@@ -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)
+               }
+       }
+}