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 <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Russ Cox 2021-12-07 11:08:57 -05:00
parent 68cbf4169f
commit fd2bfb79a1
4 changed files with 24 additions and 6 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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`