From fd2bfb79a16ae479f76e30b2ed37f28eb6c43589 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Dec 2021 11:08:57 -0500 Subject: [PATCH] go/analysis/passes/stdmethods: recognize any as alias for interface{}, for errors.As check Now that any is an alias for interface{}, we need to recognize both func (T) As(any) bool func (T) As(interface{}) bool as satisfying errors.As. For golang/go#33232. Change-Id: Ie5a992c37da8020e80367528bc23370227a70f75 Reviewed-on: https://go-review.googlesource.com/c/tools/+/369954 Trust: Russ Cox Run-TryBot: Russ Cox gopls-CI: kokoro Reviewed-by: Robert Findley --- go/analysis/passes/stdmethods/stdmethods.go | 6 ++++-- go/analysis/passes/stdmethods/testdata/src/a/a.go | 8 ++++++-- go/analysis/passes/stdmethods/testdata/src/a/b.go | 12 ++++++++++++ .../stdmethods/testdata/src/typeparams/typeparams.go | 4 ++-- 4 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 go/analysis/passes/stdmethods/testdata/src/a/b.go diff --git a/go/analysis/passes/stdmethods/stdmethods.go b/go/analysis/passes/stdmethods/stdmethods.go index 64a28ac0b9..cc9497179d 100644 --- a/go/analysis/passes/stdmethods/stdmethods.go +++ b/go/analysis/passes/stdmethods/stdmethods.go @@ -61,7 +61,7 @@ var Analyzer = &analysis.Analyzer{ // we let it go. But if it does have a fmt.ScanState, then the // rest has to match. var canonicalMethods = map[string]struct{ args, results []string }{ - "As": {[]string{"interface{}"}, []string{"bool"}}, // errors.As + "As": {[]string{"any"}, []string{"bool"}}, // errors.As // "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict "Format": {[]string{"=fmt.State", "rune"}, []string{}}, // fmt.Formatter "GobDecode": {[]string{"[]byte"}, []string{"error"}}, // gob.GobDecoder @@ -194,7 +194,9 @@ func matchParams(pass *analysis.Pass, expect []string, actual *types.Tuple, pref func matchParamType(expect string, actual types.Type) bool { expect = strings.TrimPrefix(expect, "=") // Overkill but easy. - return typeString(actual) == expect + t := typeString(actual) + return t == expect || + (t == "any" || t == "interface{}") && (expect == "any" || expect == "interface{}") } var errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) diff --git a/go/analysis/passes/stdmethods/testdata/src/a/a.go b/go/analysis/passes/stdmethods/testdata/src/a/a.go index 7f9e9ae648..c95cf5d2b7 100644 --- a/go/analysis/passes/stdmethods/testdata/src/a/a.go +++ b/go/analysis/passes/stdmethods/testdata/src/a/a.go @@ -47,7 +47,7 @@ type E int func (E) Error() string { return "" } // E implements error. -func (E) As() {} // want `method As\(\) should have signature As\(interface{}\) bool` +func (E) As() {} // want `method As\(\) should have signature As\((any|interface\{\})\) bool` func (E) Is() {} // want `method Is\(\) should have signature Is\(error\) bool` func (E) Unwrap() {} // want `method Unwrap\(\) should have signature Unwrap\(\) error` @@ -55,6 +55,10 @@ type F int func (F) Error() string { return "" } // Both F and *F implement error. -func (*F) As() {} // want `method As\(\) should have signature As\(interface{}\) bool` +func (*F) As() {} // want `method As\(\) should have signature As\((any|interface\{\})\) bool` func (*F) Is() {} // want `method Is\(\) should have signature Is\(error\) bool` func (*F) Unwrap() {} // want `method Unwrap\(\) should have signature Unwrap\(\) error` + +type G int + +func (G) As(interface{}) bool // ok diff --git a/go/analysis/passes/stdmethods/testdata/src/a/b.go b/go/analysis/passes/stdmethods/testdata/src/a/b.go new file mode 100644 index 0000000000..c0a16fb042 --- /dev/null +++ b/go/analysis/passes/stdmethods/testdata/src/a/b.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.18 +// +build go1.18 + +package a + +type H int + +func (H) As(any) bool // ok diff --git a/go/analysis/passes/stdmethods/testdata/src/typeparams/typeparams.go b/go/analysis/passes/stdmethods/testdata/src/typeparams/typeparams.go index 8ff8b350cb..72df30d496 100644 --- a/go/analysis/passes/stdmethods/testdata/src/typeparams/typeparams.go +++ b/go/analysis/passes/stdmethods/testdata/src/typeparams/typeparams.go @@ -28,7 +28,7 @@ type E[P any] int func (E[_]) Error() string { return "" } // E implements error. -func (E[P]) As() {} // want `method As\(\) should have signature As\(interface{}\) bool` +func (E[P]) As() {} // want `method As\(\) should have signature As\((any|interface\{\})\) bool` func (E[_]) Is() {} // want `method Is\(\) should have signature Is\(error\) bool` func (E[_]) Unwrap() {} // want `method Unwrap\(\) should have signature Unwrap\(\) error` @@ -36,6 +36,6 @@ type F[P any] int func (F[_]) Error() string { return "" } // Both F and *F implement error. -func (*F[_]) As() {} // want `method As\(\) should have signature As\(interface{}\) bool` +func (*F[_]) As() {} // want `method As\(\) should have signature As\((any|interface\{\})\) bool` func (*F[_]) Is() {} // want `method Is\(\) should have signature Is\(error\) bool` func (*F[_]) Unwrap() {} // want `method Unwrap\(\) should have signature Unwrap\(\) error`