From baac4d883404401db0cf4a05f2b64c828768a2e3 Mon Sep 17 00:00:00 2001 From: Will Beason Date: Tue, 10 Mar 2026 21:04:14 -0500 Subject: [PATCH] Fix todo to replace interface{} with any Resolve TODO which was set to be done after go 1.18. As the project is now in go 1.21, it seems this should be fine now. --- cmp/cmpopts/equate.go | 16 ++--- cmp/cmpopts/example_test.go | 2 +- cmp/cmpopts/ignore.go | 18 ++--- cmp/cmpopts/sort.go | 12 ++-- cmp/cmpopts/struct_filter.go | 4 +- cmp/cmpopts/util_test.go | 36 +++++----- cmp/cmpopts/xform.go | 2 +- cmp/compare.go | 8 +-- cmp/compare_test.go | 54 +++++++------- cmp/example_test.go | 14 ++-- cmp/internal/function/func_test.go | 2 +- cmp/internal/teststructs/project1.go | 2 +- cmp/internal/value/name.go | 4 +- cmp/internal/value/name_test.go | 4 +- cmp/internal/value/sort_test.go | 104 +++++++++++++-------------- cmp/options.go | 8 +-- cmp/options_test.go | 78 ++++++++++---------- cmp/report_reflect.go | 2 +- cmp/report_text.go | 8 +-- 19 files changed, 187 insertions(+), 191 deletions(-) diff --git a/cmp/cmpopts/equate.go b/cmp/cmpopts/equate.go index 3d8d0cd..565124f 100644 --- a/cmp/cmpopts/equate.go +++ b/cmp/cmpopts/equate.go @@ -15,7 +15,7 @@ import ( "github.com/google/go-cmp/cmp" ) -func equateAlways(_, _ interface{}) bool { return true } +func equateAlways(_, _ any) bool { return true } // EquateEmpty returns a [cmp.Comparer] option that determines all maps and slices // with a length of zero to be equal, regardless of whether they are nil. @@ -25,7 +25,7 @@ func EquateEmpty() cmp.Option { return cmp.FilterValues(isEmpty, cmp.Comparer(equateAlways)) } -func isEmpty(x, y interface{}) bool { +func isEmpty(x, y any) bool { vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) return (x != nil && y != nil && vx.Type() == vy.Type()) && (vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) && @@ -140,17 +140,17 @@ func EquateErrors() cmp.Option { } // areConcreteErrors reports whether x and y are types that implement error. -// The input types are deliberately of the interface{} type rather than the +// The input types are deliberately of the [any] type rather than the // error type so that we can handle situations where the current type is an -// interface{}, but the underlying concrete types both happen to implement +// [any], but the underlying concrete types both happen to implement // the error interface. -func areConcreteErrors(x, y interface{}) bool { +func areConcreteErrors(x, y any) bool { _, ok1 := x.(error) _, ok2 := y.(error) return ok1 && ok2 } -func compareErrors(x, y interface{}) bool { +func compareErrors(x, y any) bool { xe := x.(error) ye := y.(error) return errors.Is(xe, ye) || errors.Is(ye, xe) @@ -163,7 +163,7 @@ func compareErrors(x, y interface{}) bool { // safe for direct == comparison. For example, [net/netip.Addr] is documented // as being semantically safe to use with ==, while [time.Time] is documented // to discourage the use of == on time values. -func EquateComparable(typs ...interface{}) cmp.Option { +func EquateComparable(typs ...any) cmp.Option { types := make(typesFilter) for _, typ := range typs { switch t := reflect.TypeOf(typ); { @@ -182,4 +182,4 @@ type typesFilter map[reflect.Type]bool func (tf typesFilter) filter(p cmp.Path) bool { return tf[p.Last().Type()] } -func equateAny(x, y interface{}) bool { return x == y } +func equateAny(x, y any) bool { return x == y } diff --git a/cmp/cmpopts/example_test.go b/cmp/cmpopts/example_test.go index 0d19cb0..9869f02 100644 --- a/cmp/cmpopts/example_test.go +++ b/cmp/cmpopts/example_test.go @@ -127,4 +127,4 @@ var t fakeT type fakeT struct{} -func (t fakeT) Errorf(format string, args ...interface{}) { fmt.Printf(format+"\n", args...) } +func (t fakeT) Errorf(format string, args ...any) { fmt.Printf(format+"\n", args...) } diff --git a/cmp/cmpopts/ignore.go b/cmp/cmpopts/ignore.go index fb84d11..144ea23 100644 --- a/cmp/cmpopts/ignore.go +++ b/cmp/cmpopts/ignore.go @@ -21,21 +21,21 @@ import ( // // The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a // specific sub-field that is embedded or nested within the parent struct. -func IgnoreFields(typ interface{}, names ...string) cmp.Option { +func IgnoreFields(typ any, names ...string) cmp.Option { sf := newStructFilter(typ, names...) return cmp.FilterPath(sf.filter, cmp.Ignore()) } // IgnoreTypes returns an [cmp.Option] that ignores all values assignable to // certain types, which are specified by passing in a value of each type. -func IgnoreTypes(typs ...interface{}) cmp.Option { +func IgnoreTypes(typs ...any) cmp.Option { tf := newTypeFilter(typs...) return cmp.FilterPath(tf.filter, cmp.Ignore()) } type typeFilter []reflect.Type -func newTypeFilter(typs ...interface{}) (tf typeFilter) { +func newTypeFilter(typs ...any) (tf typeFilter) { for _, typ := range typs { t := reflect.TypeOf(typ) if t == nil { @@ -63,14 +63,14 @@ func (tf typeFilter) filter(p cmp.Path) bool { // values assignable to certain interface types. These interfaces are specified // by passing in an anonymous struct with the interface types embedded in it. // For example, to ignore [sync.Locker], pass in struct{sync.Locker}{}. -func IgnoreInterfaces(ifaces interface{}) cmp.Option { +func IgnoreInterfaces(ifaces any) cmp.Option { tf := newIfaceFilter(ifaces) return cmp.FilterPath(tf.filter, cmp.Ignore()) } type ifaceFilter []reflect.Type -func newIfaceFilter(ifaces interface{}) (tf ifaceFilter) { +func newIfaceFilter(ifaces any) (tf ifaceFilter) { t := reflect.TypeOf(ifaces) if ifaces == nil || t.Name() != "" || t.Kind() != reflect.Struct { panic("input must be an anonymous struct") @@ -116,14 +116,14 @@ func (tf ifaceFilter) filter(p cmp.Path) bool { // Avoid ignoring unexported fields of a type which you do not control (i.e. a // type from another repository), as changes to the implementation of such types // may change how the comparison behaves. Prefer a custom [cmp.Comparer] instead. -func IgnoreUnexported(typs ...interface{}) cmp.Option { +func IgnoreUnexported(typs ...any) cmp.Option { ux := newUnexportedFilter(typs...) return cmp.FilterPath(ux.filter, cmp.Ignore()) } type unexportedFilter struct{ m map[reflect.Type]bool } -func newUnexportedFilter(typs ...interface{}) unexportedFilter { +func newUnexportedFilter(typs ...any) unexportedFilter { ux := unexportedFilter{m: make(map[reflect.Type]bool)} for _, typ := range typs { t := reflect.TypeOf(typ) @@ -152,7 +152,7 @@ func isExported(id string) bool { // The discard function must be of the form "func(T) bool" which is used to // ignore slice elements of type V, where V is assignable to T. // Elements are ignored if the function reports true. -func IgnoreSliceElements(discardFunc interface{}) cmp.Option { +func IgnoreSliceElements(discardFunc any) cmp.Option { vf := reflect.ValueOf(discardFunc) if !function.IsType(vf.Type(), function.ValuePredicate) || vf.IsNil() { panic(fmt.Sprintf("invalid discard function: %T", discardFunc)) @@ -180,7 +180,7 @@ func IgnoreSliceElements(discardFunc interface{}) cmp.Option { // The discard function must be of the form "func(T, R) bool" which is used to // ignore map entries of type K and V, where K and V are assignable to T and R. // Entries are ignored if the function reports true. -func IgnoreMapEntries(discardFunc interface{}) cmp.Option { +func IgnoreMapEntries(discardFunc any) cmp.Option { vf := reflect.ValueOf(discardFunc) if !function.IsType(vf.Type(), function.KeyValuePredicate) || vf.IsNil() { panic(fmt.Sprintf("invalid discard function: %T", discardFunc)) diff --git a/cmp/cmpopts/sort.go b/cmp/cmpopts/sort.go index 720f3cd..76d8dd6 100644 --- a/cmp/cmpopts/sort.go +++ b/cmp/cmpopts/sort.go @@ -33,7 +33,7 @@ import ( // less or compare report inequality, their relative order is maintained. // // SortSlices can be used in conjunction with [EquateEmpty]. -func SortSlices(lessOrCompareFunc interface{}) cmp.Option { +func SortSlices(lessOrCompareFunc any) cmp.Option { vf := reflect.ValueOf(lessOrCompareFunc) if (!function.IsType(vf.Type(), function.Less) && !function.IsType(vf.Type(), function.Compare)) || vf.IsNil() { panic(fmt.Sprintf("invalid less or compare function: %T", lessOrCompareFunc)) @@ -47,7 +47,7 @@ type sliceSorter struct { fnc reflect.Value // func(T, T) bool } -func (ss sliceSorter) filter(x, y interface{}) bool { +func (ss sliceSorter) filter(x, y any) bool { vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) if !(x != nil && y != nil && vx.Type() == vy.Type()) || !(vx.Kind() == reflect.Slice && vx.Type().Elem().AssignableTo(ss.in)) || @@ -60,7 +60,7 @@ func (ss sliceSorter) filter(x, y interface{}) bool { ok2 := sort.SliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) }) return !ok1 || !ok2 } -func (ss sliceSorter) sort(x interface{}) interface{} { +func (ss sliceSorter) sort(x any) any { src := reflect.ValueOf(x) dst := reflect.MakeSlice(src.Type(), src.Len(), src.Len()) for i := 0; i < src.Len(); i++ { @@ -116,7 +116,7 @@ func (ss sliceSorter) less(v reflect.Value, i, j int) bool { // - Total: if x != y, then compare(x, y) != 0 // // SortMaps can be used in conjunction with [EquateEmpty]. -func SortMaps(lessOrCompareFunc interface{}) cmp.Option { +func SortMaps(lessOrCompareFunc any) cmp.Option { vf := reflect.ValueOf(lessOrCompareFunc) if (!function.IsType(vf.Type(), function.Less) && !function.IsType(vf.Type(), function.Compare)) || vf.IsNil() { panic(fmt.Sprintf("invalid less or compare function: %T", lessOrCompareFunc)) @@ -130,13 +130,13 @@ type mapSorter struct { fnc reflect.Value // func(T, T) bool } -func (ms mapSorter) filter(x, y interface{}) bool { +func (ms mapSorter) filter(x, y any) bool { vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) return (x != nil && y != nil && vx.Type() == vy.Type()) && (vx.Kind() == reflect.Map && vx.Type().Key().AssignableTo(ms.in)) && (vx.Len() != 0 || vy.Len() != 0) } -func (ms mapSorter) sort(x interface{}) interface{} { +func (ms mapSorter) sort(x any) any { src := reflect.ValueOf(x) outType := reflect.StructOf([]reflect.StructField{ {Name: "K", Type: src.Type().Key()}, diff --git a/cmp/cmpopts/struct_filter.go b/cmp/cmpopts/struct_filter.go index ca11a40..fd9e7b0 100644 --- a/cmp/cmpopts/struct_filter.go +++ b/cmp/cmpopts/struct_filter.go @@ -18,7 +18,7 @@ import ( // // The name may be a dot-delimited string (e.g., "Foo.Bar") to select a // specific sub-field that is embedded or nested within the parent struct. -func filterField(typ interface{}, name string, opt cmp.Option) cmp.Option { +func filterField(typ any, name string, opt cmp.Option) cmp.Option { // TODO: This is currently unexported over concerns of how helper filters // can be composed together easily. // TODO: Add tests for FilterField. @@ -32,7 +32,7 @@ type structFilter struct { ft fieldTree // Tree of fields to match on } -func newStructFilter(typ interface{}, names ...string) structFilter { +func newStructFilter(typ any, names ...string) structFilter { // TODO: Perhaps allow * as a special identifier to allow ignoring any // number of path steps until the next field match? // This could be useful when a concrete struct gets transformed into diff --git a/cmp/cmpopts/util_test.go b/cmp/cmpopts/util_test.go index 8c74d65..6c3066d 100644 --- a/cmp/cmpopts/util_test.go +++ b/cmp/cmpopts/util_test.go @@ -66,7 +66,7 @@ type ( ParentStruct } - EmptyInterface interface{} + EmptyInterface any ) func TestOptions(t *testing.T) { @@ -99,7 +99,7 @@ func TestOptions(t *testing.T) { tests := []struct { label string // Test name - x, y interface{} // Input values to compare + x, y any // Input values to compare opts []cmp.Option // Input options wantEqual bool // Whether the inputs are equal wantPanic bool // Whether Equal should panic @@ -868,28 +868,28 @@ func TestOptions(t *testing.T) { reason: "equal because mismatching unexported fields are ignored", }, { label: "IgnoreTypes", - x: []interface{}{5, "same"}, - y: []interface{}{6, "same"}, + x: []any{5, "same"}, + y: []any{6, "same"}, wantEqual: false, reason: "not equal because 5 != 6", }, { label: "IgnoreTypes", - x: []interface{}{5, "same"}, - y: []interface{}{6, "same"}, + x: []any{5, "same"}, + y: []any{6, "same"}, opts: []cmp.Option{IgnoreTypes(0)}, wantEqual: true, reason: "equal because ints are ignored", }, { label: "IgnoreTypes+IgnoreInterfaces", - x: []interface{}{5, "same", new(bytes.Buffer)}, - y: []interface{}{6, "same", new(bytes.Buffer)}, + x: []any{5, "same", new(bytes.Buffer)}, + y: []any{6, "same", new(bytes.Buffer)}, opts: []cmp.Option{IgnoreTypes(0)}, wantPanic: true, reason: "panics because bytes.Buffer has unexported fields", }, { label: "IgnoreTypes+IgnoreInterfaces", - x: []interface{}{5, "same", new(bytes.Buffer)}, - y: []interface{}{6, "diff", new(bytes.Buffer)}, + x: []any{5, "same", new(bytes.Buffer)}, + y: []any{6, "diff", new(bytes.Buffer)}, opts: []cmp.Option{ IgnoreTypes(0, ""), IgnoreInterfaces(struct{ io.Reader }{}), @@ -898,8 +898,8 @@ func TestOptions(t *testing.T) { reason: "equal because bytes.Buffer is ignored by match on interface type", }, { label: "IgnoreTypes+IgnoreInterfaces", - x: []interface{}{5, "same", new(bytes.Buffer)}, - y: []interface{}{6, "same", new(bytes.Buffer)}, + x: []any{5, "same", new(bytes.Buffer)}, + y: []any{6, "same", new(bytes.Buffer)}, opts: []cmp.Option{ IgnoreTypes(0, ""), IgnoreInterfaces(struct { @@ -1170,13 +1170,13 @@ func TestOptions(t *testing.T) { } func TestPanic(t *testing.T) { - args := func(x ...interface{}) []interface{} { return x } + args := func(x ...any) []any { return x } tests := []struct { - label string // Test name - fnc interface{} // Option function to call - args []interface{} // Arguments to pass in - wantPanic string // Expected panic message - reason string // The reason for the expected outcome + label string // Test name + fnc any // Option function to call + args []any // Arguments to pass in + wantPanic string // Expected panic message + reason string // The reason for the expected outcome }{{ label: "EquateApprox", fnc: EquateApprox, diff --git a/cmp/cmpopts/xform.go b/cmp/cmpopts/xform.go index 25b4bd0..2ad8701 100644 --- a/cmp/cmpopts/xform.go +++ b/cmp/cmpopts/xform.go @@ -30,7 +30,7 @@ func (xf xformFilter) filter(p cmp.Path) bool { // // Had this been an unfiltered [cmp.Transformer] instead, this would result in an // infinite cycle converting a string to []string to [][]string and so on. -func AcyclicTransformer(name string, xformFunc interface{}) cmp.Option { +func AcyclicTransformer(name string, xformFunc any) cmp.Option { xf := xformFilter{cmp.Transformer(name, xformFunc)} return cmp.FilterPath(xf.filter, xf.xform) } diff --git a/cmp/compare.go b/cmp/compare.go index 0f5b8a4..e505cad 100644 --- a/cmp/compare.go +++ b/cmp/compare.go @@ -41,8 +41,6 @@ import ( "github.com/google/go-cmp/cmp/internal/value" ) -// TODO(≥go1.18): Use any instead of interface{}. - // Equal reports whether x and y are equal by recursively applying the // following rules in the given order to x and y and all of their sub-values: // @@ -92,7 +90,7 @@ import ( // is checked to detect whether the address has already been visited. // If there is a cycle, then the pointed at values are considered equal // only if both addresses were previously visited in the same path step. -func Equal(x, y interface{}, opts ...Option) bool { +func Equal(x, y any, opts ...Option) bool { s := newState(opts) s.compareAny(rootStep(x, y)) return s.result.Equal() @@ -112,7 +110,7 @@ func Equal(x, y interface{}, opts ...Option) bool { // // Do not depend on this output being stable. If you need the ability to // programmatically interpret the difference, consider using a custom Reporter. -func Diff(x, y interface{}, opts ...Option) string { +func Diff(x, y any, opts ...Option) string { s := newState(opts) // Optimization: If there are no other reporters, we can optimize for the @@ -138,7 +136,7 @@ func Diff(x, y interface{}, opts ...Option) string { // rootStep constructs the first path step. If x and y have differing types, // then they are stored within an empty interface type. -func rootStep(x, y interface{}) PathStep { +func rootStep(x, y any) PathStep { vx := reflect.ValueOf(x) vy := reflect.ValueOf(y) diff --git a/cmp/compare_test.go b/cmp/compare_test.go index 03615df..cbe2d9a 100644 --- a/cmp/compare_test.go +++ b/cmp/compare_test.go @@ -114,7 +114,7 @@ func (s Stringer) String() string { return string(s) } type test struct { label string // Test name - x, y interface{} // Input values to compare + x, y any // Input values to compare opts []cmp.Option // Input options wantEqual bool // Whether any difference is expected wantPanic string // Sub-string of an expected panic message @@ -261,14 +261,14 @@ func comparerTests() []test { label: label + "/UnfilteredCompare", x: 1, y: 1, - opts: []cmp.Option{cmp.Comparer(func(_, _ interface{}) bool { return true })}, + opts: []cmp.Option{cmp.Comparer(func(_, _ any) bool { return true })}, wantPanic: "cannot use an unfiltered option", reason: "unfiltered options are functionally useless", }, { label: label + "/UnfilteredTransform", x: 1, y: 1, - opts: []cmp.Option{cmp.Transformer("λ", func(x interface{}) interface{} { return x })}, + opts: []cmp.Option{cmp.Transformer("λ", func(x any) any { return x })}, wantPanic: "cannot use an unfiltered option", reason: "unfiltered options are functionally useless", }, { @@ -594,8 +594,8 @@ func comparerTests() []test { reason: "function call using Go reflection should automatically convert assignable interfaces; see https://golang.org/issues/22143", }, { label: label + "/DynamicMap", - 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"}}, + x: []any{map[string]any{"avg": 0.278, "hr": 65, "name": "Mark McGwire"}, map[string]any{"avg": 0.288, "hr": 63, "name": "Sammy Sosa"}}, + y: []any{map[string]any{"avg": 0.278, "hr": 65.0, "name": "Mark McGwire"}, map[string]any{"avg": 0.288, "hr": 63.0, "name": "Sammy Sosa"}}, wantEqual: false, reason: "dynamic map with differing types (but semantically equivalent values) should be inequal", }, { @@ -721,7 +721,7 @@ func transformerTests() []test { const label = "Transformer" - transformOnce := func(name string, f interface{}) cmp.Option { + transformOnce := func(name string, f any) cmp.Option { xform := cmp.Transformer(name, f) return cmp.FilterPath(func(p cmp.Path) bool { for _, ps := range p { @@ -775,7 +775,7 @@ func transformerTests() []test { x: 0, y: 1, opts: []cmp.Option{ - cmp.Transformer("λ", func(in int) interface{} { + cmp.Transformer("λ", func(in int) any { if in == 0 { return "zero" } @@ -815,7 +815,7 @@ func transformerTests() []test { "number":"212 555-1234"},{"type":"office","number":"646 555-4567"},{ "type":"mobile","number":"123 456-7890"}],"children":[],"spouse":null}`, opts: []cmp.Option{ - transformOnce("ParseJSON", func(s string) (m map[string]interface{}) { + transformOnce("ParseJSON", func(s string) (m map[string]any) { if err := json.Unmarshal([]byte(s), &m); err != nil { panic(err) } @@ -978,12 +978,12 @@ func reporterTests() []test { reason: "reporter should display the slice header to disambiguate between the two slice values", }, { label: label + "/AmbiguousStringerMapKey", - x: map[interface{}]string{ + x: map[any]string{ nil: "nil", Stringer("hello"): "goodbye", foo1.Bar{"fizz"}: "buzz", }, - y: map[interface{}]string{ + y: map[any]string{ newStringer("hello"): "goodbye", foo2.Bar{"fizz"}: "buzz", }, @@ -991,8 +991,8 @@ func reporterTests() []test { reason: "reporter should avoid calling String to disambiguate between the two map keys", }, { label: label + "/NonAmbiguousStringerMapKey", - x: map[interface{}]string{Stringer("hello"): "goodbye"}, - y: map[interface{}]string{newStringer("fizz"): "buzz"}, + x: map[any]string{Stringer("hello"): "goodbye"}, + y: map[any]string{newStringer("fizz"): "buzz"}, wantEqual: false, reason: "reporter should call String as there is no ambiguity between the two map keys", }, { @@ -1291,19 +1291,19 @@ using the AllowUnexported option.`, "\n"), reason: "printing map keys should have some verbosity limit imposed", }, { label: label + "/LargeStringInInterface", - x: struct{ X interface{} }{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis."}, + x: struct{ X any }{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis."}, - y: struct{ X interface{} }{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis,"}, + y: struct{ X any }{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis,"}, reason: "strings within an interface should benefit from specialized diffing", }, { label: label + "/LargeBytesInInterface", - x: struct{ X interface{} }{[]byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis.")}, - y: struct{ X interface{} }{[]byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis,")}, + x: struct{ X any }{[]byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis.")}, + y: struct{ X any }{[]byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis,")}, reason: "bytes slice within an interface should benefit from specialized diffing", }, { label: label + "/LargeStandaloneString", - x: struct{ X interface{} }{[1]string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis."}}, - y: struct{ X interface{} }{[1]string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis,"}}, + x: struct{ X any }{[1]string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis."}}, + y: struct{ X any }{[1]string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis,"}}, reason: "printing a large standalone string that is different should print enough context to see the difference", }, { label: label + "/SurroundingEqualElements", @@ -1359,8 +1359,8 @@ using the AllowUnexported option.`, "\n"), var v string = "hello" return &v }(), - y: func() *interface{} { - var v interface{} = "hello" + y: func() *any { + var v any = "hello" return &v }(), reason: "mismatched types between any and *any should print differently", @@ -1377,13 +1377,13 @@ using the AllowUnexported option.`, "\n"), reason: "mismatched pointer types should print differently", }, { label: label + "/MapStringAny", - x: map[string]interface{}{"key": int(0)}, - y: map[string]interface{}{"key": uint(0)}, + x: map[string]any{"key": int(0)}, + y: map[string]any{"key": uint(0)}, reason: "mismatched underlying value within interface", }, { label: label + "/StructFieldAny", - x: struct{ X interface{} }{int(0)}, - y: struct{ X interface{} }{uint(0)}, + x: struct{ X any }{int(0)}, + y: struct{ X any }{uint(0)}, reason: "mismatched underlying value within interface", }, { label: label + "/SliceOfBytesText", @@ -2026,7 +2026,7 @@ func methodTests() []test { tf.In(0).AssignableTo(tf.In(1)) && tf.Out(0) == reflect.TypeOf(true) } return false - }, cmp.Transformer("Addr", func(x interface{}) interface{} { + }, cmp.Transformer("Addr", func(x any) any { v := reflect.ValueOf(x) vp := reflect.New(v.Type()) vp.Elem().Set(v) @@ -2451,7 +2451,7 @@ func cycleTests() []test { } var tests []test - type XY struct{ x, y interface{} } + type XY struct{ x, y any } for _, tt := range []struct { label string in XY @@ -2589,7 +2589,7 @@ func project1Tests() []test { Desc: "some description", Dreamers: []ts.Dreamer{{}, { Name: "dreamer2", - Animal: []interface{}{ + Animal: []any{ ts.Goat{ Target: "corporation", Immutable: &ts.GoatImmutable{ diff --git a/cmp/example_test.go b/cmp/example_test.go index 318143b..ad69277 100644 --- a/cmp/example_test.go +++ b/cmp/example_test.go @@ -121,7 +121,7 @@ func ExampleOption_equalNaNs() { // This example is for demonstrative purposes; // use [github.com/google/go-cmp/cmp/cmpopts.EquateApprox] instead. func ExampleOption_equalNaNsAndApproximateFloats() { - alwaysEqual := cmp.Comparer(func(_, _ interface{}) bool { return true }) + alwaysEqual := cmp.Comparer(func(_, _ any) bool { return true }) opts := cmp.Options{ // This option declares that a float64 comparison is equal only if @@ -161,10 +161,10 @@ func ExampleOption_equalNaNsAndApproximateFloats() { // This example is for demonstrative purposes; // use [github.com/google/go-cmp/cmp/cmpopts.EquateEmpty] instead. func ExampleOption_equalEmpty() { - alwaysEqual := cmp.Comparer(func(_, _ interface{}) bool { return true }) + alwaysEqual := cmp.Comparer(func(_, _ any) bool { return true }) // This option handles slices and maps of any type. - opt := cmp.FilterValues(func(x, y interface{}) bool { + opt := cmp.FilterValues(func(x, y any) bool { vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) return (vx.IsValid() && vy.IsValid() && vx.Type() == vy.Type()) && (vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) && @@ -283,13 +283,13 @@ func ExampleOption_transformComplex() { }), } - x := []interface{}{ + x := []any{ complex128(3.0), complex64(5.1 + 2.9i), float32(-1.2), float64(12.3), } - y := []interface{}{ + y := []any{ complex128(3.1), complex64(4.9 + 3.1i), float32(-1.3), float64(11.7), } - z := []interface{}{ + z := []any{ complex128(3.8), complex64(4.9 + 3.1i), float32(-1.3), float64(11.7), } @@ -377,4 +377,4 @@ var t fakeT type fakeT struct{} -func (t fakeT) Errorf(format string, args ...interface{}) { fmt.Printf(format+"\n", args...) } +func (t fakeT) Errorf(format string, args ...any) { fmt.Printf(format+"\n", args...) } diff --git a/cmp/internal/function/func_test.go b/cmp/internal/function/func_test.go index f03ef45..eb87e9e 100644 --- a/cmp/internal/function/func_test.go +++ b/cmp/internal/function/func_test.go @@ -20,7 +20,7 @@ func (*myType) PointerMethod() {} func TestNameOf(t *testing.T) { tests := []struct { - fnc interface{} + fnc any want string }{ {TestNameOf, "function.TestNameOf"}, diff --git a/cmp/internal/teststructs/project1.go b/cmp/internal/teststructs/project1.go index 223d6ab..c683763 100644 --- a/cmp/internal/teststructs/project1.go +++ b/cmp/internal/teststructs/project1.go @@ -167,7 +167,7 @@ type Dreamer struct { PreSlaps []Slap ContSlaps []Slap ContSlapsInterval int32 - Animal []interface{} // Could be either Goat or Donkey + Animal []any // Could be either Goat or Donkey Ornamental bool Amoeba int64 Heroes int32 diff --git a/cmp/internal/value/name.go b/cmp/internal/value/name.go index 7b498bb..fe82356 100644 --- a/cmp/internal/value/name.go +++ b/cmp/internal/value/name.go @@ -9,7 +9,7 @@ import ( "strconv" ) -var anyType = reflect.TypeOf((*interface{})(nil)).Elem() +var anyType = reflect.TypeOf((*any)(nil)).Elem() // TypeString is nearly identical to reflect.Type.String, // but has an additional option to specify that full type names be used. @@ -21,8 +21,6 @@ func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte // BUG: Go reflection provides no way to disambiguate two named types // of the same name and within the same package, // but declared within the namespace of different functions. - - // Use the "any" alias instead of "interface{}" for better readability. if t == anyType { return append(b, "any"...) } diff --git a/cmp/internal/value/name_test.go b/cmp/internal/value/name_test.go index c177e72..c93990a 100644 --- a/cmp/internal/value/name_test.go +++ b/cmp/internal/value/name_test.go @@ -16,7 +16,7 @@ var pkgPath = reflect.TypeOf(Named{}).PkgPath() func TestTypeString(t *testing.T) { tests := []struct { - in interface{} + in any want string }{{ in: bool(false), @@ -110,7 +110,7 @@ func TestTypeString(t *testing.T) { in: (*Named)(nil), want: "*$PackagePath.Named", }, { - in: (*interface{})(nil), + in: (*any)(nil), want: "*any", }, { in: (*interface{ Read([]byte) (int, error) })(nil), diff --git a/cmp/internal/value/sort_test.go b/cmp/internal/value/sort_test.go index 26222d6..3120947 100644 --- a/cmp/internal/value/sort_test.go +++ b/cmp/internal/value/sort_test.go @@ -45,58 +45,58 @@ func TestSortKeys(t *testing.T) { cmp.Comparer(func(x, y chan bool) bool { return true }), cmp.Comparer(func(x, y chan int) bool { return true }), cmp.Comparer(func(x, y chan float64) bool { return true }), - cmp.Comparer(func(x, y chan interface{}) bool { return true }), + cmp.Comparer(func(x, y chan any) bool { return true }), cmp.Comparer(func(x, y *int) bool { return true }), } tests := []struct { - in map[interface{}]bool // Set of keys to sort - want []interface{} + in map[any]bool // Set of keys to sort + want []any }{{ - in: map[interface{}]bool{1: true, 2: true, 3: true}, - want: []interface{}{1, 2, 3}, + in: map[any]bool{1: true, 2: true, 3: true}, + want: []any{1, 2, 3}, }, { - in: map[interface{}]bool{ - nil: true, - true: true, - false: true, - -5: true, - -55: true, - -555: true, - uint(1): true, - uint(11): true, - uint(111): true, - "abc": true, - "abcd": true, - "abcde": true, - "foo": true, - "bar": true, - MyString("abc"): true, - MyString("abcd"): true, - MyString("abcde"): true, - new(int): true, - new(int): true, - make(chan bool): true, - make(chan bool): true, - make(chan int): true, - make(chan interface{}): true, - math.Inf(+1): true, - math.Inf(-1): true, - 1.2345: true, - 12.345: true, - 123.45: true, - 1234.5: true, - 0 + 0i: true, - 1 + 0i: true, - 2 + 0i: true, - 0 + 1i: true, - 0 + 2i: true, - 0 + 3i: true, - [2]int{2, 3}: true, - [2]int{4, 0}: true, - [2]int{2, 4}: true, - MyArray([2]int{2, 4}): true, - EmptyStruct{}: true, + in: map[any]bool{ + nil: true, + true: true, + false: true, + -5: true, + -55: true, + -555: true, + uint(1): true, + uint(11): true, + uint(111): true, + "abc": true, + "abcd": true, + "abcde": true, + "foo": true, + "bar": true, + MyString("abc"): true, + MyString("abcd"): true, + MyString("abcde"): true, + new(int): true, + new(int): true, + make(chan bool): true, + make(chan bool): true, + make(chan int): true, + make(chan any): true, + math.Inf(+1): true, + math.Inf(-1): true, + 1.2345: true, + 12.345: true, + 123.45: true, + 1234.5: true, + 0 + 0i: true, + 1 + 0i: true, + 2 + 0i: true, + 0 + 1i: true, + 0 + 2i: true, + 0 + 3i: true, + [2]int{2, 3}: true, + [2]int{4, 0}: true, + [2]int{2, 4}: true, + MyArray([2]int{2, 4}): true, + EmptyStruct{}: true, MyStruct{ "bravo", [2]int{2, 3}, make(chan float64), }: true, @@ -104,13 +104,13 @@ func TestSortKeys(t *testing.T) { "alpha", [2]int{3, 3}, make(chan float64), }: true, }, - want: []interface{}{ + want: []any{ nil, false, true, -555, -55, -5, uint(1), uint(11), uint(111), math.Inf(-1), 1.2345, 12.345, 123.45, 1234.5, math.Inf(+1), (0 + 0i), (0 + 1i), (0 + 2i), (0 + 3i), (1 + 0i), (2 + 0i), [2]int{2, 3}, [2]int{2, 4}, [2]int{4, 0}, MyArray([2]int{2, 4}), - make(chan bool), make(chan bool), make(chan int), make(chan interface{}), + make(chan bool), make(chan bool), make(chan int), make(chan any), new(int), new(int), "abc", "abcd", "abcde", "bar", "foo", MyString("abc"), MyString("abcd"), MyString("abcde"), @@ -122,7 +122,7 @@ func TestSortKeys(t *testing.T) { // NaN values cannot be properly deduplicated. // This is okay since map entries with NaN in the keys cannot be // retrieved anyways. - in: map[interface{}]bool{ + in: map[any]bool{ math.NaN(): true, math.NaN(): true, complex(0, math.NaN()): true, @@ -131,7 +131,7 @@ func TestSortKeys(t *testing.T) { complex(math.NaN(), 0): true, complex(math.NaN(), math.NaN()): true, }, - want: []interface{}{ + want: []any{ math.NaN(), complex(math.NaN(), math.NaN()), complex(math.NaN(), 0), @@ -142,13 +142,13 @@ func TestSortKeys(t *testing.T) { for i, tt := range tests { // Intentionally pass the map via an unexported field to detect panics. // Unfortunately, we cannot actually test the keys without using unsafe. - v := reflect.ValueOf(struct{ x map[interface{}]bool }{tt.in}).Field(0) + v := reflect.ValueOf(struct{ x map[any]bool }{tt.in}).Field(0) value.SortKeys(append(v.MapKeys(), v.MapKeys()...)) // Try again, with keys that have read-write access in reflect. v = reflect.ValueOf(tt.in) keys := append(v.MapKeys(), v.MapKeys()...) - var got []interface{} + var got []any for _, k := range value.SortKeys(keys) { got = append(got, k.Interface()) } diff --git a/cmp/options.go b/cmp/options.go index ba3fce8..3e66674 100644 --- a/cmp/options.go +++ b/cmp/options.go @@ -156,7 +156,7 @@ func (f pathFilter) String() string { // // The option passed in may be an [Ignore], [Transformer], [Comparer], [Options], or // a previously filtered [Option]. -func FilterValues(f interface{}, opt Option) Option { +func FilterValues(f any, opt Option) Option { v := reflect.ValueOf(f) if !function.IsType(v.Type(), function.ValueFilter) || v.IsNil() { panic(fmt.Sprintf("invalid values filter function: %T", f)) @@ -285,7 +285,7 @@ var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`) // transformation [PathStep] (and eventually shown in the [Diff] output). // The name must be a valid identifier or qualified identifier in Go syntax. // If empty, an arbitrary name is used. -func Transformer(name string, f interface{}) Option { +func Transformer(name string, f any) Option { v := reflect.ValueOf(f) if !function.IsType(v.Type(), function.Transformer) || v.IsNil() { panic(fmt.Sprintf("invalid transformer function: %T", f)) @@ -352,7 +352,7 @@ func (tr transformer) String() string { // - Symmetric: equal(x, y) == equal(y, x) // - Deterministic: equal(x, y) == equal(x, y) // - Pure: equal(x, y) does not modify x or y -func Comparer(f interface{}) Option { +func Comparer(f any) Option { v := reflect.ValueOf(f) if !function.IsType(v.Type(), function.Equal) || v.IsNil() { panic(fmt.Sprintf("invalid comparer function: %T", f)) @@ -427,7 +427,7 @@ func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableO // unexported fields of the specified struct types. // // See [Exporter] for the proper use of this option. -func AllowUnexported(types ...interface{}) Option { +func AllowUnexported(types ...any) Option { m := make(map[reflect.Type]bool) for _, typ := range types { t := reflect.TypeOf(typ) diff --git a/cmp/options_test.go b/cmp/options_test.go index c7d45f3..b58f56e 100644 --- a/cmp/options_test.go +++ b/cmp/options_test.go @@ -18,168 +18,168 @@ import ( func TestOptionPanic(t *testing.T) { type myBool bool tests := []struct { - label string // Test description - fnc interface{} // Option function to call - args []interface{} // Arguments to pass in - wantPanic string // Expected panic message + label string // Test description + fnc any // Option function to call + args []any // Arguments to pass in + wantPanic string // Expected panic message }{{ label: "AllowUnexported", fnc: AllowUnexported, - args: []interface{}{}, + args: []any{}, }, { label: "AllowUnexported", fnc: AllowUnexported, - args: []interface{}{1}, + args: []any{1}, wantPanic: "invalid struct type", }, { label: "AllowUnexported", fnc: AllowUnexported, - args: []interface{}{ts.StructA{}}, + args: []any{ts.StructA{}}, }, { label: "AllowUnexported", fnc: AllowUnexported, - args: []interface{}{ts.StructA{}, ts.StructB{}, ts.StructA{}}, + args: []any{ts.StructA{}, ts.StructB{}, ts.StructA{}}, }, { label: "AllowUnexported", fnc: AllowUnexported, - args: []interface{}{ts.StructA{}, &ts.StructB{}, ts.StructA{}}, + args: []any{ts.StructA{}, &ts.StructB{}, ts.StructA{}}, wantPanic: "invalid struct type", }, { label: "Comparer", fnc: Comparer, - args: []interface{}{5}, + args: []any{5}, wantPanic: "invalid comparer function", }, { label: "Comparer", fnc: Comparer, - args: []interface{}{func(x, y interface{}) bool { return true }}, + args: []any{func(x, y any) bool { return true }}, }, { label: "Comparer", fnc: Comparer, - args: []interface{}{func(x, y io.Reader) bool { return true }}, + args: []any{func(x, y io.Reader) bool { return true }}, }, { label: "Comparer", fnc: Comparer, - args: []interface{}{func(x, y io.Reader) myBool { return true }}, + args: []any{func(x, y io.Reader) myBool { return true }}, wantPanic: "invalid comparer function", }, { label: "Comparer", fnc: Comparer, - args: []interface{}{func(x string, y interface{}) bool { return true }}, + args: []any{func(x string, y any) bool { return true }}, wantPanic: "invalid comparer function", }, { label: "Comparer", fnc: Comparer, - args: []interface{}{(func(int, int) bool)(nil)}, + args: []any{(func(int, int) bool)(nil)}, wantPanic: "invalid comparer function", }, { label: "Transformer", fnc: Transformer, - args: []interface{}{"", 0}, + args: []any{"", 0}, wantPanic: "invalid transformer function", }, { label: "Transformer", fnc: Transformer, - args: []interface{}{"", func(int) int { return 0 }}, + args: []any{"", func(int) int { return 0 }}, }, { label: "Transformer", fnc: Transformer, - args: []interface{}{"", func(bool) bool { return true }}, + args: []any{"", func(bool) bool { return true }}, }, { label: "Transformer", fnc: Transformer, - args: []interface{}{"", func(int) bool { return true }}, + args: []any{"", func(int) bool { return true }}, }, { label: "Transformer", fnc: Transformer, - args: []interface{}{"", func(int, int) bool { return true }}, + args: []any{"", func(int, int) bool { return true }}, wantPanic: "invalid transformer function", }, { label: "Transformer", fnc: Transformer, - args: []interface{}{"", (func(int) uint)(nil)}, + args: []any{"", (func(int) uint)(nil)}, wantPanic: "invalid transformer function", }, { label: "Transformer", fnc: Transformer, - args: []interface{}{"Func", func(Path) Path { return nil }}, + args: []any{"Func", func(Path) Path { return nil }}, }, { label: "Transformer", fnc: Transformer, - args: []interface{}{"世界", func(int) bool { return true }}, + args: []any{"世界", func(int) bool { return true }}, }, { label: "Transformer", fnc: Transformer, - args: []interface{}{"/*", func(int) bool { return true }}, + args: []any{"/*", func(int) bool { return true }}, wantPanic: "invalid name", }, { label: "Transformer", fnc: Transformer, - args: []interface{}{"_", func(int) bool { return true }}, + args: []any{"_", func(int) bool { return true }}, }, { label: "FilterPath", fnc: FilterPath, - args: []interface{}{(func(Path) bool)(nil), Ignore()}, + args: []any{(func(Path) bool)(nil), Ignore()}, wantPanic: "invalid path filter function", }, { label: "FilterPath", fnc: FilterPath, - args: []interface{}{func(Path) bool { return true }, Ignore()}, + args: []any{func(Path) bool { return true }, Ignore()}, }, { label: "FilterPath", fnc: FilterPath, - args: []interface{}{func(Path) bool { return true }, Reporter(&defaultReporter{})}, + args: []any{func(Path) bool { return true }, Reporter(&defaultReporter{})}, wantPanic: "invalid option type", }, { label: "FilterPath", fnc: FilterPath, - args: []interface{}{func(Path) bool { return true }, Options{Ignore(), Ignore()}}, + args: []any{func(Path) bool { return true }, Options{Ignore(), Ignore()}}, }, { label: "FilterPath", fnc: FilterPath, - args: []interface{}{func(Path) bool { return true }, Options{Ignore(), Reporter(&defaultReporter{})}}, + args: []any{func(Path) bool { return true }, Options{Ignore(), Reporter(&defaultReporter{})}}, wantPanic: "invalid option type", }, { label: "FilterValues", fnc: FilterValues, - args: []interface{}{0, Ignore()}, + args: []any{0, Ignore()}, wantPanic: "invalid values filter function", }, { label: "FilterValues", fnc: FilterValues, - args: []interface{}{func(x, y int) bool { return true }, Ignore()}, + args: []any{func(x, y int) bool { return true }, Ignore()}, }, { label: "FilterValues", fnc: FilterValues, - args: []interface{}{func(x, y interface{}) bool { return true }, Ignore()}, + args: []any{func(x, y any) bool { return true }, Ignore()}, }, { label: "FilterValues", fnc: FilterValues, - args: []interface{}{func(x, y interface{}) myBool { return true }, Ignore()}, + args: []any{func(x, y any) myBool { return true }, Ignore()}, wantPanic: "invalid values filter function", }, { label: "FilterValues", fnc: FilterValues, - args: []interface{}{func(x io.Reader, y interface{}) bool { return true }, Ignore()}, + args: []any{func(x io.Reader, y any) bool { return true }, Ignore()}, wantPanic: "invalid values filter function", }, { label: "FilterValues", fnc: FilterValues, - args: []interface{}{(func(int, int) bool)(nil), Ignore()}, + args: []any{(func(int, int) bool)(nil), Ignore()}, wantPanic: "invalid values filter function", }, { label: "FilterValues", fnc: FilterValues, - args: []interface{}{func(int, int) bool { return true }, Reporter(&defaultReporter{})}, + args: []any{func(int, int) bool { return true }, Reporter(&defaultReporter{})}, wantPanic: "invalid option type", }, { label: "FilterValues", fnc: FilterValues, - args: []interface{}{func(int, int) bool { return true }, Options{Ignore(), Ignore()}}, + args: []any{func(int, int) bool { return true }, Options{Ignore(), Ignore()}}, }, { label: "FilterValues", fnc: FilterValues, - args: []interface{}{func(int, int) bool { return true }, Options{Ignore(), Reporter(&defaultReporter{})}}, + args: []any{func(int, int) bool { return true }, Options{Ignore(), Reporter(&defaultReporter{})}}, wantPanic: "invalid option type", }} diff --git a/cmp/report_reflect.go b/cmp/report_reflect.go index e39f422..3c57526 100644 --- a/cmp/report_reflect.go +++ b/cmp/report_reflect.go @@ -17,7 +17,7 @@ import ( ) var ( - anyType = reflect.TypeOf((*interface{})(nil)).Elem() + anyType = reflect.TypeOf((*any)(nil)).Elem() stringType = reflect.TypeOf((*string)(nil)).Elem() bytesType = reflect.TypeOf((*[]byte)(nil)).Elem() byteType = reflect.TypeOf((*byte)(nil)).Elem() diff --git a/cmp/report_text.go b/cmp/report_text.go index 388fcf5..6717fd4 100644 --- a/cmp/report_text.go +++ b/cmp/report_text.go @@ -94,10 +94,10 @@ type textNode interface { // textWrap is a wrapper that concatenates a prefix and/or a suffix // to the underlying node. type textWrap struct { - Prefix string // e.g., "bytes.Buffer{" - Value textNode // textWrap | textList | textLine - Suffix string // e.g., "}" - Metadata interface{} // arbitrary metadata; has no effect on formatting + Prefix string // e.g., "bytes.Buffer{" + Value textNode // textWrap | textList | textLine + Suffix string // e.g., "}" + Metadata any // arbitrary metadata; has no effect on formatting } func (s *textWrap) Len() int {